问:Java 枚举类比较用 == 还是 equals,有啥区别?
答:java 枚举值比较用 == 和 equals 方法没啥区别,两个随便用都是一样的效果。因为枚举 Enum 类的 equals 方法默认实现就是通过 == 来比较的;类似的 Enum 的 compareTo 方法比较的是 Enum 的 ordinal 顺序大小;类似的还有 Enum 的 name 方法和 toString 方法一样都返回的是 Enum 的 name 值。
问:简单谈谈你理解的 Java 枚举本质原理?
答:java 枚举的本质原理是通过普通类来实现的,只是编译器为我们进行了加工处理,每个枚举类型编译后的字节码实质都继承自 java.lang.Enum 的枚举类型同名普通类,而每个枚举常量实质是一个枚举类型同名普通类的静态常量对象,所有枚举常量都通过静态代码块进行初始化实例赋值(由于是静态块,所以在类加载期间就初始化了)。为了加深理解可以通过下面的例子说明:
public enum Status {
START("a"),
RUNNING("b"),
STOP();
private Status() {
this("def");
}
private Status(String name) {
this.name = name;
}
public String name;
}
我们对如上枚举类型进行 javac 编译后通过 javap -v Status.class 可以查看其编译后字节码如下:
......
public final class Status extends java.lang.Enum<Status>
......
{
//枚举类型值都成了Status类型类的静态常量成员属性
public static final Status START;
public static final Status RUNNING;
public static final Status STOP;
public java.lang.String name;
public static Status[] values();
......
public static Status valueOf(java.lang.String);
......
//静态代码块,类加载时执行
static {};
flags: ACC_STATIC
Code:
stack=5, locals=0, args_size=0
//创建一个Status对象通过参数为字符串常量"a"的构造方法初始化赋值给START
0: new #4 // class Status
3: dup
4: ldc #10 // String START
6: iconst_0
7: ldc #11 // String a
9: invokespecial #7 // Method "<init>":(Ljava/lang/String;ILjava/lang/String;)V
12: putstatic #12 // Field START:LStatus;
......
}
上面例子已经解释的很清楚了,记住枚举的本质是编译器处理成了类,枚举值为类的静态常量属性,其属性在类加载时的静态代码块中被初始化实例赋值。枚举可以有修饰符不大于默认修饰符的构造方法(修饰符可为 private,不可为 public 等)等,枚举只是一种语法糖,被编译器生成了最终的类而已。
所以枚举类型其实和我们自己使用 Java 普通类实现的类似,如下:
public class Status {
public static final Status START;
public static final Status RUNNING;
public static final Status STOP;
static {
START = new Status("a");
RUNNING = new Status("b");
STOP = new Status();
}
private Status() {
this("def");
}
private Status(String name) {
this.name = name;
}
public String name;
}
所以从某种意义上可以说 JDK 1.5 后引入的枚举类型是上面枚举常量类的代码封装而已。
问:Java 枚举类与常量的区别有哪些,有啥优缺点?
答:枚举相对于常量类来说定义更简单,其不需要定义枚举值,而常量类中的每个常量必须要手动添加值。枚举作为参数使用时可以在编译时避免弱类型错误,而常量类中的常量作为参数使用时在编译时无法避免弱类型错误(譬如常量类型为 int,参数传递一个常量类中没定义的 int 值)。枚举自动具备内置方法(如 values 方法可以获得所有值的集合来遍历,ordinal 方法可以获得排序值,compareTo 方法可以基于 ordinal 比较),而常量类默认不具备这些方法。枚举的缺点就是不能被继承(编译后生成的类是 final class 的),也不能通过 extends 继承其他类(枚举类编译后实质就是继承了 Enum 类,Java 是单继承机制),但是定义的枚举类可以通过 implements 实现其他接口,枚举值定义完毕后除非修改重构,否则无法做扩展,而常量类可以随意继承。
戛然而止!这是 Part 1 部分,Part 2 部分请明早准时抄收~~
老铁们,别嫌短,长了你肯定不会看完的,所以这就是码农每日一题的宗旨(其他历史文章请查看公众号历史记录)~
看完分享一波嘛,和你的小伙伴一起讨论才更加有意思,右上角分享 666~
看个笑话放松一下
“这位同学,请问你知道《边城》吗?”“呸!别跟我提编程,老子这辈子最讨厌的就是编程!”
It's lucky to gain and fated to miss.
得之,我幸。不得,我命。