枚举的定义
public enum AccountActionTypeEnum {LOGIN,REGISTER,EDIT\_INFO;private AccountActionTypeEnum() {}}
值个别是大写的字母,多个值之间以逗号分隔。
枚举常量在类型安全性和便捷性都很有保障,如果呈现类型问题编译器也会提醒咱们改良。上面看看如何在其余类中应用枚举类型
public static void main(String[] args){//间接援用AccountActionTypeEnum type =AccountActionTypeEnum.LOGIN;}
枚举实现原理
咱们大略理解了枚举类型的定义与简略应用后,当初来理解一下枚举类型的根本实现原理。实际上在应用关键字enum创立枚举类型并编译后,编译器会为咱们生成一个相干的类,这个类继承了Java API中的java.lang.Enum类,也就是说通过关键字enum创立枚举类型在编译后事实上也是一个类类型而且该类继承自java.lang.Enum类。上面咱们编译后面定义的AccountActionTypeEnum.java并查看生成的class文件来验证这个论断:
javac AccountActionTypeEnum.java #编译java文件生成AccountActionTypeEnum.class文件
而后通过jad来反编译AccountActionTypeEnum.class
.jad -sjava .AccountActionTypeEnum.class #我这里的jad.exe放在AccountActionTypeEnum的同级目录,如果有退出环境变量的话,能够间接jad
反编译AccountActionTypeEnum.class的后果
// Decompiled by Jad v1.5.8g. Copyright 2001 Pavel Kouznetsov.// Jad home page: http://www.kpdus.com/jad.html// Decompiler options: packimports(3)// Source File Name: AccountActionTypeEnum.java<br>public final class AccountActionTypeEnum extends Enum{// 编译器重写的办法public static AccountActionTypeEnum[] values(){return (AccountActionTypeEnum[])$VALUES.clone();}// 编译器重写的办法public static AccountActionTypeEnum valueOf(String s){return (AccountActionTypeEnum)Enum.valueOf(AccountActionTypeEnum, s);}// 公有private AccountActionTypeEnum(String s, int i){ // 调用enum的构造方法super(s, i);}// 定义的四种枚举// 定义类变量,这也就是为什么咱们能够间接以AccountActionTypeEnum.LOGIN的模式应用的起因了public static final AccountActionTypeEnum LOGIN;public static final AccountActionTypeEnum REGISTER;public static final AccountActionTypeEnum EDIT\_INFO;private static final AccountActionTypeEnum $VALUES[];//动态代码块复制初始化类变量,在初始化阶段执行,实例化枚举实例static{LOGIN = new AccountActionTypeEnum("LOGIN", 0);REGISTER = new AccountActionTypeEnum("REGISTER", 1);EDIT\_INFO = new AccountActionTypeEnum("EDIT\_INFO", 2);$VALUES = (new AccountActionTypeEnum[] {LOGIN, REGISTER, EDIT\_INFO});}}
从反编译的代码能够看出编译器的确帮忙咱们生成了一个AccountActionTypeEnum类(留神该类是final类型的,将无奈被继承)而且该类继承自java.lang.Enum类,该类是一个抽象类,除此之外,编译器还帮忙咱们生成了4个AccountActionTypeEnum类型的实例对象别离对应枚举中定义的三种type和一个type数组。留神编译器还为咱们生成了两个静态方法,别离是values()和 valueOf(),到此咱们也就明确了,应用关键字enum定义的枚举类型,在编译期后,也将转换成为一个实实在在的类,而在该类中,会存在每个在枚举类型中定义好变量的对应实例对象,如上述的LOGIN枚举类型对应public static final AccountActionTypeEnum LOGIN;,同时编译器会为该类创立两个办法,别离是values()和valueOf()。上面咱们深刻理解一下java.lang.Enum类以及values()和valueOf()的用处。
Enum抽象类常见办法
Enum是所有 Java 语言枚举类型的公共根本类(留神Enum是抽象类),以下是它的常见办法:
返回类型 | 办法名称 | 办法阐明 |
---|---|---|
int | compareTo(E o) | 比拟此枚举与指定对象的程序 |
boolean | equals(Object other) | 当指定对象等于此枚举常量时,返回 true。 |
Class<?> | getDeclaringClass() | 返回与此枚举常量的枚举类型绝对应的 Class 对象 |
String | name() | 返回此枚举常量的名称,在其枚举申明中对其进行申明 |
int | ordinal() | 返回枚举常量的序数(它在枚举申明中的地位,其中初始常量序数为零) |
String | toString() | 返回枚举常量的名称,它蕴含在申明中 |
static<T extends Enum<T>> T | static valueOf(Class<T> enumType, String name) | 返回带指定名称的指定枚举类型的枚举常量。 |
这里次要阐明一下ordinal()
办法,该办法获取的是枚举变量在枚举类中申明的程序,下标从0开始,如AccountActionTypeEnum中的LOGIN在第一个地位,那么LOGIN的ordinal值就是0,如果LOGIN的申明地位发生变化,那么ordinal办法获取到的值也随之变动,留神在大多数状况下咱们都不应该首先应用该办法,毕竟它总是变幻莫测的。如果咱们把LOGIN放在第二个地位,那么它的ordinal办法的值也会相应的扭转,上面咱们将LOGIN扭转地位编译,而后从新反编译AccountActionTypeEnum.class文件。
新的AccountActionTypeEnum.class的动态代码块
static{REGISTER = new AccountActionTypeEnum("REGISTER", 0);// 能够看到当咱们把LOGIN放在第二个地位,那么它的ordinal的值也就变成了1,那么`ordinal()`的值也会变成1了。LOGIN = new AccountActionTypeEnum("LOGIN", 1);EDIT\_INFO = new AccountActionTypeEnum("EDIT\_INFO", 2);$VALUES = (new AccountActionTypeEnum[] {REGISTER, LOGIN, EDIT\_INFO});}
values办法返回类变量$VALUES[],也就是所以枚举对象的数组。咱们能够通过这个办法遍历定义的三种枚举。
valueOf办法调用的是父类Enum的静态方法valueOf,返回对应name的枚举类变量。
如:
AccountActionTypeEnum.valueOf("LOGIN") => AccountActionTypeEnum.LOGIN
Enum源码
//实现了Comparablepublic abstract class Enum\<E extends Enum>implements Comparable, Serializable {<br>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 self = this;if (self.getClass() != other.getClass() && // optimizationself.getDeclaringClass() != other.getDeclaringClass())throw new ClassCastException();return self.ordinal - other.ordinal;//依据ordinal值比拟大小}@SuppressWarnings("unchecked")public final Class getDeclaringClass() {//获取class对象援用,getClass()是Object的办法Class<?> clazz = getClass();//获取父类Class对象援用Class<?> zuper = clazz.getSuperclass();return (zuper == Enum.class) ? (Class)clazz : (Class)zuper;}<br>public static \<T extends Enum> T valueOf(Class 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关键字定义枚举,其余事件就交给编译器吧。