enum枚举类型

    Think in Java这本书,不得不说的确是经典,但是今天看到了枚举,实在忍不住吐槽了,感觉书上的内容完全没有讲出enum的用法,百度后写此博客。

    enum定义的枚举类就是class,其定义方法不是通过继承,我们用关键字enum来声明枚举类型,不可以通过显式继承该抽象类的方式来声明,并且该类是一个不可以被继承的final类。其枚举值都是该枚举类的类静态常量,注意:这些枚举值都是public static final的,所以可以通过可以通过 Enum 类型名直接引用该常量,如 类名.常量名,因此枚举类中的枚举值最好全部大写。

    一个枚举类的枚举对象里面的值都必须是唯一的,可以把相同类型的常量分组到一个枚举类型里。枚举的一个突出优点在于它能够保证单例,它的这个优点让它和switch成了绝配,在jdk1.5之前,switch只能支持int和char类型,局限了switch的使用范围。当switch可以和enum搭配使用的时候,这个限制被突破了,理论上我们可以借助enum对任意具有相同类型的对象使用switch。

    Think in java上这一节的练习是创建一个包含纸币最小类型的enum并为其写一个switch语句,对于每一个case输出该特定货币的描述,这个问题很好的解释了enum的作用,最小货币就是0.1,0.2,0.5,1,2,5这些double数据,如果没有enum的配合,switch是不能接受double型作为变量的,下面在代码中讲解enum的用法。

首先是enum的定义类

 

[java]  view plain  copy
 
  1. /* 枚举也可以象一般的类一样添加方法和属性, 
  2.  * 你可以为它添加静态和非静态的属性或方法, 
  3.  * 这一切都象你在一般的类中做的那样. 
  4.  * 枚举类是通过enum关键字声明来定义的 */  
  5. public enum Enum_Money {  
  6.      // 枚举列表必须写在最前面,否则编译出错,枚举列表只支持String类型,但是允许在枚举值后用括号添加构造。如果只是最普通的枚举没有其他方法枚举结尾可以不加分号,否则必须加  
  7.     Not(0.1),MILD(0.2),MEDIUM(0.5),HOT(1),FLAMING(2);  
  8.     private double money;  
  9.     /*通过括号赋值,而且必须有带参构造器和一属性跟方法,否则编译出错 
  10.      * 赋值必须是都赋值或都不赋值,不能一部分赋值一部分不赋值 
  11.      * 如果不赋值则不能写构造器,赋值编译也出错*/  
  12.     //构造器默认也只能是private, 从而保证构造函数只能在内部使用  
  13.     Enum_Money(double money){  
  14.         this.money=money;  
  15.     }  
  16.       
  17.     public double getReturn(){  
  18.         return money;  
  19.     }  
  20.       
  21. }  
   然后是调用类

 

 

[java]  view plain  copy
 
  1. public class Test_Enum {  
  2.   
  3.    public static void main(String[] ARGS){  
  4.        /*通过values()获得枚举值的数组,按照enum常量声明的顺序*/  
  5.        for(Enum_Money money:Enum_Money.values())  
  6.            /*ordinal()返回枚举值在枚举中的索引位置,从0开始,顺序为enum声明的顺序*/  
  7.            System.out.println(money.getReturn()+" "+money.ordinal());  
  8.        /* 
  9.         * 枚举类型是一种类型,用于定义变量,以限制变量的赋值 赋值时通过"枚举名.值"来取得相关枚举中的值 
  10.         */  
  11.        Enum_Money money = Enum_Money.MEDIUM;  
  12.        switch (money) {  
  13.     case Not:  
  14.         System.out.println("1毛");  
  15.         break;  
  16.     case MEDIUM:   
  17.         System.out.println("2毛");  
  18.         break;  
  19.     default:  
  20.         break;  
  21.     }  
  22.    }  
  23.       
  24. }  
  25.     

 

   下面是enum类的源码分析

1. public abstract class Enum<E extends Enum<E>>  

2.         implements Comparable<E>, Serializable {  

3.       

4.     private final String name;  

5.   

6.     // 当前枚举常量名称  

7.     public final String name() {  

8.     return name;  

9.     }  

10.   

11.     private final int ordinal;  

12.   

13.     // 当前枚举常量次序,从0开始  

14.     public final int ordinal() {  

15.     return ordinal;  

16.     }  

17.   

18.     // 专有构造器,我们无法调用。该构造方法用于由响应枚举类型声明的编译器发出的代码。   

19.     protected Enum(String name, int ordinal) {  

20.     this.name = name;  

21.     this.ordinal = ordinal;  

22.     }  

23.   

24.     // 返回枚举常量的名称,默认是返回name值。可以重写该方法,输出更加友好的描述。  

25.     public String toString() {  

26.     return name;  

27.     }  

28.   

29.     // 比较当前枚举常量是否和指定的对象相等。因为枚举常量是单例的,所以直接调用==操作符。子类不可以重写该方法。  

30.     public final boolean equals(Object other) {   

31.         return this==other;  

32.     }  

33.   

34.     // 返回该枚举常量的哈希码。和equals一致,该方法不可以被重写。  

35.     public final int hashCode() {  

36.         return super.hashCode();  

37.     }  

38.   

39.     // 因为枚举常量是单例的,所以不允许克隆。  

40.     protected final Object clone() throws CloneNotSupportedException {  

41.     throw new CloneNotSupportedException();  

42.     }  

43.   

44.     // 比较该枚举常量和指定对象的大小。它们的类型要相同,根据它们在枚举声明中的先后顺序来返回大小(前面的小,后面的大)。子类不可以重写该方法  

45.     public final int compareTo(E o) {  

46.     Enum other = (Enum)o;  

47.     Enum self = this;  

48.     if (self.getClass() != other.getClass() && // optimization  

49.             self.getDeclaringClass() != other.getDeclaringClass())  

50.         throw new ClassCastException();  

51.     return self.ordinal - other.ordinal;  

52.     }  

53.   

54.     // 得到枚举常量所属枚举类型的Class对象  

55.     public final Class<E> getDeclaringClass() {  

56.     Class clazz = getClass();  

57.     Class zuper = clazz.getSuperclass();  

58.     return (zuper == Enum.class) ? clazz : zuper;  

59.     }  

60.   

61.     // 返回带指定名称的指定枚举类型的枚举常量。名称必须与在此类型中声明枚举常量所用的标识符完全匹配。不允许使用额外的空白字符。  

62.     public static <T extends Enum<T>> T valueOf(Class<T> enumType,  

63.                                                 String name) {  

64.         T result = enumType.enumConstantDirectory().get(name);  

65.         if (result != null)  

66.             return result;  

67.         if (name == null)  

68.             throw new NullPointerException("Name is null");  

69.         throw new IllegalArgumentException(  

70.             "No enum const " + enumType +"." + name);  

71.     }  

72.   

73.     // 不允许反序列化枚举对象  

74.     private void readObject(ObjectInputStream in) throws IOException,  

75.         ClassNotFoundException {  

76.             throw new InvalidObjectException("can't deserialize enum");  

77.     }  

78.   

79.     // 不允许反序列化枚举对象  

80.     private void readObjectNoData() throws ObjectStreamException {  

81.         throw new InvalidObjectException("can't deserialize enum");  

82.     }  

83.   

84.     // 枚举类不可以有finalize方法,子类不可以重写该方法  

85.     protected final void finalize() { }  

86. }