到此对于抽象类Enum类的基本内容就介绍完了,这里提醒大家一点,Enum类内部会有一个构造函数,该构造函数只能有编译器调用,我们是无法手动操作的,不妨看看Enum类的主要源码:
//实现了Comparable public abstract class Enum<E extends Enum<E>> implements Comparable<E>, Serializable { private final String name; //枚举字符串名称 public final String name() { return name; } private final int ordinal;//枚举顺序值 public final int ordinal() { return ordinal; } //枚举的构造方法,只能由编译器调用 protected Enum(String name, int ordinal) { this.name = name; this.ordinal = ordinal; } public String toString() { return name; } public final boolean equals(Object other) { return this==other; } //比较的是ordinal值 public final int compareTo(E o) { Enum<?> other = (Enum<?>)o; Enum<E> self = this; if (self.getClass() != other.getClass() && // optimization self.getDeclaringClass() != other.getDeclaringClass()) throw new ClassCastException(); return self.ordinal - other.ordinal;//根据ordinal值比较大小 } @SuppressWarnings("unchecked") public final Class<E> getDeclaringClass() { //获取class对象引用,getClass()是Object的方法 Class<?> clazz = getClass(); //获取父类Class对象引用 Class<?> zuper = clazz.getSuperclass(); return (zuper == Enum.class) ? (Class<E>)clazz : (Class<E>)zuper; } public static <T extends Enum<T>> T valueOf(Class<T> enumType, String name) { //enumType.enumConstantDirectory()获取到的是一个map集合,key值就是name值,value则是枚举变量值 //enumConstantDirectory是class对象内部的方法,根据class对象获取一个map集合的值 T result = enumType.enumConstantDirectory().get(name); if (result != null) return result; if (name == null) throw new NullPointerException("Name is null"); throw new IllegalArgumentException( "No enum constant " + enumType.getCanonicalName() + "." + name); } //.....省略其他没用的方法 }
通过Enum源码,可以知道,Enum实现了Comparable接口,这也是可以使用compareTo比较的原因,当然Enum构造函数也是存在的,该函数只能由编译器调用,毕竟我们只能使用enum关键字定义枚举,其他事情就放心交给编译器吧。
//由编译器调用 protected Enum(String name, int ordinal) { this.name = name; this.ordinal = ordinal; }
编译器生成的Values方法与ValueOf方法
values()方法和valueOf(String name)方法是编译器生成的static方法,因此从前面的分析中,在Enum类中并没出现values()方法,但valueOf()方法还是有出现的,只不过编译器生成的valueOf()方法需传递一个name参数,而Enum自带的静态方法valueOf()则需要传递两个方法,从前面反编译后的代码可以看出,编译器生成的valueOf方法最终还是调用了Enum类的valueOf方法,下面通过代码来演示这两个方法的作用:
Day[] days2 = Day.values(); System.out.println("day2:"+Arrays.toString(days2)); Day day = Day.valueOf("MONDAY"); System.out.println("day:"+day); /** 输出结果: day2:[MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY] day:MONDAY */
从结果可知道,values()方法的作用就是获取枚举类中的所有变量,并作为数组返回,而valueOf(String name)方法与Enum类中的valueOf方法的作用类似根据名称获取枚举变量,只不过编译器生成的valueOf方法更简洁些只需传递一个参数。这里我们还必须注意到,由于values()方法是由编译器插入到枚举类中的static方法,所以如果我们将枚举实例向上转型为Enum,那么values()方法将无法被调用,因为Enum类中并没有values()方法,valueOf()方法也是同样的道理,注意是一个参数的。
//正常使用 Day[] ds=Day.values(); //向上转型Enum Enum e = Day.MONDAY; //无法调用,没有此方法 //e.values();
二、枚举与Class对象
上述我们提到当枚举实例向上转型为Enum类型后,values()方法将会失效,也就无法一次性获取所有枚举实例变量,但是由于Class对象的存在,即使不使用values()方法,还是有可能一次获取到所有枚举实例变量的,在Class对象中存在如下方法:
因此通过getEnumConstants()方法,同样可以轻而易举地获取所有枚举实例变量下面通过代码来演示这个功能:
//正常使用 Day[] ds=Day.values(); //向上转型Enum Enum e = Day.MONDAY; //无法调用,没有此方法 //e.values(); //获取class对象引用 Class<?> clasz = e.getDeclaringClass(); if(clasz.isEnum()) { Day[] dsz = (Day[]) clasz.getEnumConstants(); System.out.println("dsz:"+Arrays.toString(dsz)); } /** 输出结果: dsz:[MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY] */
正如上述代码所展示,通过Enum的class对象的getEnumConstants方法,我们仍能一次性获取所有的枚举实例常量。
三、枚举与switch
关于枚举与switch是个比较简单的话题,使用switch进行条件判断时,条件参数一般只能是整型,字符型。而枚举型确实也被switch所支持,在java 1.7后switch也对字符串进行了支持。这里我们简单看一下switch与枚举类型的使用:
enum Color {GREEN,RED,BLUE} public class EnumDemo4 { public static void printName(Color color){ switch (color){ case BLUE: //无需使用Color进行引用 System.out.println("蓝色"); break; case RED: System.out.println("红色"); break; case GREEN: System.out.println("绿色"); break; } } public static void main(String[] args){ printName(Color.BLUE); printName(Color.RED); printName(Color.GREEN); //蓝色 //红色 //绿色 } }
需要注意的是使用在于switch条件进行结合使用时,无需使用Color引用。