黑马程序员技术交流社区

标题: JDK1.5增加了枚举,那么如何来理解枚举这一新特性? [打印本页]

作者: 于汝国    时间: 2011-12-22 12:37
标题: JDK1.5增加了枚举,那么如何来理解枚举这一新特性?
本帖最后由 于汝国 于 2011-12-22 23:49 编辑

JDK1.5增加了枚举,那么如何来理解枚举这一新特性,它有什么独特的优势,具体使用在什么地方,解决什么样的问题?求详解......
作者: 陈帅雷    时间: 2011-12-22 12:49
本帖最后由 陈帅雷 于 2011-12-22 12:52 编辑

Enum的最简单形式,即类似于:

  public enum Color {

  Red,

  Green,

  Blue;

  }

  Enum是Sun全新引进的一个关键字,看起来很象是特殊的class,它也可以有自己的变量,可以定义自己的方法,可以实现一个或者多个接口。在声明一个enum类型时,应该注意到enum类型有如下的一些特征:

  1.它不能有public的构造函数,这样做可以保证客户代码没有办法新建一个enum的实例;

  2.所有枚举值都是public , static , final的。(注意:这一点只是针对于枚举值,可以和在普通类里面定义变量一样定义其它任何类型的非枚举变量,这些变量可以用任何你想用的修饰符。);

  3.Enum默认实现了java.lang.Comparable接口;

  4.Enum重载了toString方法,因此如果调用Color.Blue.toString()默认返回字符串”Blue”;

  5.Enum提供了一个valueOf方法,它和toString方法是相对应的。调用valueOf(“Blue”)将返回Color.Blue。因此在重写toString方法的时候就要注意到这一点,一般来说应该相对应地重写valueOf方法;

  6.Enum还提供了values方法,该方法可以方便的遍历所有的枚举值;

  7.Enum还有一个oridinal的方法,该方法返回枚举值在枚举类中的顺序,这个顺序根据枚举值声明的顺序而定,这里Color.Red.ordinal()返回0。

  了解了这些基本特性。

  1.遍历所有有枚举值. 知道了有values方法,可以轻车熟路地用ForEach循环来遍历了枚举值了。

  for (Color c: Color.values())

  System.out.println(“find value:” + c);

  2.在enum中定义方法和变量,比如可以为Color增加一个方法随机返回一个颜色。

  public enum Color {

  Red,

  Green,

  Blue;

  /*

  *定义一个变量表示枚举值的数目。

  *(我有点奇怪为什么sun没有给enum直接提供一个size方法).

  */

  private static int number = Color.values().length ;

  /**

  * 随机返回一个枚举值

  @return a random enum value.

  */

  public static Color getRandomColor(){

  long random = System.currentTimeMillis() % number;

  switch ((int) random){

  case 0:

  return Color.Red;

  case 1:

  return Color.Green;

  case 2:

  return Color.Blue;

  default : return Color.Red;

  }

  }

  }

  可以看出这在枚举类型里定义变量和方法和在普通类里面定义方法和变量没有什么区别。唯一要注意的只是变量和方法定义必须放在所有枚举值定义的后面,否则编译器会给出一个错误。
3.覆载(Override)toString, valueOf方法。

  前面已经知道enum提供了toString,valueOf等方法,很多时候都需要覆载默认的toString方法,那么对于enum怎么做呢。其实这和覆载一个普通class的toString方法没有什么区别。

  ….

  public String toString(){

  switch (this){

  case Red:

  return "Color.Red";

  case Green:

  return "Color.Green";

  case Blue:

  return "Color.Blue";

  default:

  return "Unknow Color";

  }

  }

  ….

  这时可以看到,此时再用前面的遍历代码打印出来的是

  Color.Red

  Color.Green

  Color.Blue

  而不是

  Red

  Green

  Blue.

  可以看到toString确实是被覆载了。一般来说在覆载toString的时候同时也应该覆载valueOf方法,以保持它们相互的一致性。

  4.使用构造函数。

  虽然enum不可以有public的构造函数,但是还是可以定义private的构造函数,在enum内部使用。还是用Color这个例子。

  public enum Color {

  Red("This is Red"),

  Green("This is Green"),

  Blue("This is Blue");

  private String desc;

  Color(String desc){

  this.desc = desc;

  }

  public String getDesc(){

  return this.desc;

  }

  }

  这里为每一个颜色提供了一个说明信息, 然后定义了一个构造函数接受这个说明信息。

  要注意这里构造函数不能为public或者protected, 从而保证构造函数只能在内部使用,客户代码不能new一个枚举值的实例出来。这也是完全符合情理的,因为知道枚举值是public static final的常量而已。

  5.实现特定的接口

  已经知道enum可以定义变量和方法,它要实现一个接口也和普通class实现一个接口一样,这里就不作示例了。

  6.定义枚举值自己的方法。

  前面看到可以为enum定义一些方法,其实甚至可以为每一个枚举值定义方法。这样,前面覆载 toString的例子可以被改写成这样。

  public enum Color {

  Red {

  public String toString(){

  return "Color.Red";

  }

  },

  Green {

  public String toString(){

  return "Color.Green";

  }

  },

  Blue{

  public String toString(){

  return "Color.Blue";

  }

  };

  }

  从逻辑上来说这样比原先提供一个“全局“的toString方法要清晰一些。

作者: 黑马巩伟伟    时间: 2011-12-22 12:51
Enum作为Sun全新引进的一个关键字,看起来很象是特殊的class,    它也可以有自己的变量,可以定义自己的方法,可以实现一个或者多个接口。    当我们在声明一个enum类型时,我们应该注意到enum类型有如下的一些特征。     
   
     1.它不能有public的构造函数,这样做可以保证客户代码没有办法新建一个enum的实例。     
   
     2.所有枚举值都是public    ,    static    ,    final的。注意这一点只是针对于枚举值,我们可以和在普通类里面定义    变量一样定义其它任何类型的非枚举变量,这些变量可以用任何你想用的修饰符。     
   
     3.Enum默认实现了java.lang.Comparable接口。     
   
     4.Enum覆载了了toString方法,因此我们如果调用Color.Blue.toString()默认返回字符串”Blue”.     
   
     5.Enum提供了一个valueOf方法,这个方法和toString方法是相对应的。调用valueOf(“Blue”)将返回Color.Blue.因此我们在自己重写toString方法的时候就要注意到这一点,一把来说应该相对应地重写valueOf方法。     
   
     6.Enum还提供了values方法,这个方法使你能够方便的遍历所有的枚举值。     
   
     7.Enum还有一个oridinal的方法,这个方法返回枚举值在枚举类种的顺序,这个顺序根据枚举值声明的顺序而定,这里Color.Red.ordinal()返回0。     

作者: 冯瑞君老师    时间: 2011-12-22 15:08
public class TestEnum {
    /*最普通的枚举*/
    public enum ColorSelect {
        red, green, yellow, blue;   
    }

    /* 枚举也可以象一般的类一样添加方法和属性,你可以为它添加静态和非静态的属性或方法,这一切都象你在一般的类中做的那样. */
    public enum Season {
        // 枚举列表必须写在最前面,否则编译出错
        winter, spring, summer, fall;

        private final static String location = "Phoenix";        

        public static Season getBest() {
            if (location.equals("Phoenix"))
                return winter;
            else
                return summer;
        }
    }
    /*还可以有构造方法*/
    public enum Temp {
        /*通过括号赋值,而且必须有带参构造器和一属性跟方法,否则编译出错
         * 赋值必须是都赋值或都不赋值,不能一部分赋值一部分不赋值
         * 如果不赋值则不能写构造器,赋值编译也出错*/
        absoluteZero(-459), freezing(32),boiling(212), paperBurns(451);
        
        private final int value;
        public int getValue() {
            return value;
        }
        //构造器默认也只能是private, 从而保证构造函数只能在内部使用
        Temp(int value) {
            this.value = value;
        }
    }

    public static void main(String[] args) {
        /*
         * 枚举类型是一种类型,用于定义变量,以限制变量的赋值 赋值时通过"枚举名.值"来取得相关枚举中的值
         */
        ColorSelect m = ColorSelect.blue;
        switch (m) {
        /*注意:枚举重写了ToString(),说以枚举变量的值是不带前缀的
          *所以为blue而非ColorSelect.blue
          */
   case red:
            System.out.println("color is red");
            break;
        case green:
            System.out.println("color is green");
            break;
        case yellow:
            System.out.println("color is yellow");
            break;
        case blue:
            System.out.println("color is blue");
            break;
        }
        System.out.println("遍历ColorSelect中的值");
        /*通过values()获得枚举值的数组*/
        for (ColorSelect c : ColorSelect.values()) {
            System.out.println(c);
        } 
   System.out.println("枚举ColorSelect中的值有:"+ColorSelect.values().length+"个");
  /*ordinal()返回枚举值在枚举中的索引位置,从0开始*/
  System.out.println(ColorSelect.red.ordinal());//0
  System.out.println(ColorSelect.green.ordinal());//1
  System.out.println(ColorSelect.yellow.ordinal());//2
  System.out.println(ColorSelect.blue.ordinal());//3

  /*枚举默认实现了java.lang.Comparable接口*/
  System.out.println(ColorSelect.red.compareTo(ColorSelect.green));

  System.out.println(Season.getBest());
        
        for(Temp t:Temp.values()){
            /*通过getValue()取得相关枚举的值*/
            System.out.println(t+"的值是"+t.getValue());
        }

    }
}
作者: 于汝国    时间: 2011-12-22 23:50
谢谢大家哈!我会仔细学习下的!
作者: 王德云    时间: 2011-12-23 00:02
强烈建议楼主认真看完老师的视频后,认真提出学习中的疑问
然后,我们大家共同去解决和探讨。这样更有效果。谢谢~~{:soso_e100:}
作者: 袁泽宇    时间: 2011-12-23 13:40
枚举是一种规范
它规范了参数的形式,这样就可以不用考虑类型的不匹配
并且显示的替代了int型参数可能带来的模糊概念  

浅薄的理解




欢迎光临 黑马程序员技术交流社区 (http://bbs.itheima.com/) 黑马程序员IT技术论坛 X3.2