关于java8:理解枚举类型

37次阅读

共计 4828 个字符,预计需要花费 13 分钟才能阅读完成。

枚举的定义

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 源码

// 实现了 Comparable
public 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() && // optimization
self.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 关键字定义枚举,其余事件就交给编译器吧。

正文完
 0