1 简述你对枚举的理解
枚举是 JDK5 版本新增的特性(泛型、For-each等如今被广泛应用的特性也是由 JDK5 时所新增的),另外到了 JDK6 后 switch 语句支持枚举类型。
枚举具有以下特征:
- 使用关键字 enum
- 枚举可以单独定义在一个文件中,也可以嵌在其它Java类中
- 枚举可以实现一个或多个接口(Interface)
- 枚举可以定义新的变量
- 枚举可以定义新的方法
- 枚举可以定义根据具体枚举值而相异的类
- 枚举不能被继承
2 枚举与常量类的区别
使用枚举的方式定义常量让代码更具有可读性,运行进行编译时检查,预先设定可接收值的范围,避免因为传入非法值导致的意外问题。
常量类 | 枚举 | |
---|---|---|
编译时 | 常量类编译时,是直接把常量的值编译到类的二进制代码里,常量的值在升级中变化后,需要重新编译引用常量的类,因为里面存的是旧值。 | 枚举类编译时,没有把常量值编译到代码里,即使常量的值发生变化,也不会影响引用常量的类。 |
编译后 | 常量类可被继承修改、增加字段等,容易导致父类的不兼容。 | 枚举类编译后默认为 final-class ,不允许继承,防止被子类修改。 |
比较 | 当使用常量类时,往往通过 equals 去判断两者是否相等。 | 枚举类确保JVM只存在一个常量实例,即常量值地址唯一,可以用==直接对比,性能会有提高。 |
switch 语句 | 当 switch 使用 int 、 String 类型时,由于值的不稳定性往往会有越界的现象,对于这个的处理往往只能通过 if 条件筛选以及 default 模块来处理。 | 使用枚举型后,在编译期间限定类型,不允许发生越界的情况。 |
3 枚举的本质
枚举类在编译后会生成一个新的final class,这个类继承于 java.lang.Enum 。当一个 Java 类第一次被使用时,静态资源会被初始化,而 Java 类的加载以及初始化过程都是线程安全的,所以创建一个枚举类是线程安全的。
枚举类在用于单例模式时可以有效地执行单例。请见Java 利用枚举实现单例模式
4 枚举与序列化的关系
在使用单例模式时,绝大多数单例的实现方式一旦实现了 Serializable 接口后,由于反射的存在,单例特性被破坏,每次调用 readObject 方法返回的都是一个新创建的对象。
Java 对枚举做了特殊规定,使得每一个枚举类定义的枚举变量在 JVM 中都是唯一的。在序列化的时候 Java 仅仅是将枚举对象的 name 属性输出到结果中,反序列化的时候则是通过 java.lang.Enum 的valueOf 方法来根据名字查找枚举对象。同时,编译器是不允许任何对这种序列化机制的定制的,因此禁用了 writeObject、readObject、readObjectNoData、writeReplace和readResolve等方法。
5 在switch语句中使用枚举类型
直接看一个例子。
package org.example;
public class EnumTest3 {
// 创建一个枚举类
enum State {
MONDAY,
TUESDAY,
WEDNESDAY,
THURSDAY,
FRIDAY,
SATURDAY,
SUNDAY;
}
private State state;
public State getState() {
return state;
}
public void setState(State state) {
this.state = state;
}
// 根据枚举类的属性取对应的值
public int getTime() {
switch (state) {
case MONDAY:
return 1;
case TUESDAY:
return 2;
case WEDNESDAY:
return 3;
case THURSDAY:
return 4;
case FRIDAY:
return 5;
case SATURDAY:
return 6;
case SUNDAY:
return 7;
}
return 0;
}
public static void main(String[] args) {
EnumTest3 e = new EnumTest3();
e.setState(State.FRIDAY);
int time = e.getTime();
System.out.println(time);
}
}
6 枚举类代替if/switch
- 定义一个任务接口。
- 定义枚举类,并实现任务接口。
- 设置属性的同时,实现任务接口中指定的任务。
- 定义一个getInstance方法,指定获取枚举类属性的方法
- 使用枚举类对象。
具体步骤如下代码所示:
package org.example;
// 利用Enum类替换if/switch
public class EnumTest4 {
// 新建一个接口,定义需要执行的任务
public interface getTime {
int getTodayTime();
void sayHello();
}
// 定义枚举类的同时,实现每个属性对应的任务
enum State implements getTime {
MONDAY (1) {
@Override
public int getTodayTime() {
return 111;
}
@Override
public void sayHello() {
System.out.println("今天是星期一");
}
},
TUESDAY (2) {
@Override
public int getTodayTime() {
return 222;
}
@Override
public void sayHello() {
System.out.println("今天是星期二");
}
},
WEDNESDAY (3) {
@Override
public int getTodayTime() {
return 333;
}
@Override
public void sayHello() {
System.out.println("今天是星期三");
}
},
THURSDAY (4) {
@Override
public int getTodayTime() {
return 444;
}
@Override
public void sayHello() {
System.out.println("今天是星期四");
}
},
FRIDAY (5) {
@Override
public int getTodayTime() {
return 555;
}
@Override
public void sayHello() {
System.out.println("今天是星期五");
}
},
SATURDAY (6) {
@Override
public int getTodayTime() {
return 666;
}
@Override
public void sayHello() {
System.out.println("今天是星期六");
}
},
SUNDAY (7) {
@Override
public int getTodayTime() {
return 777;
}
@Override
public void sayHello() {
System.out.println("今天是星期天");
}
};
// 定义Enum的参数,用于判断具体调用哪个属性
int time;
State(int i) {
this.time = i;
}
// 返回指定的Enum属性对象
public static State getInstance(int time) {
// 遍历Enum定义的属性
for (State state : State.values()) {
// 如果有相等的,则返回对应的属性
if (state.time == time) {
return state;
}
}
return null;
}
}
public static void main(String[] args) {
// 使用枚举类代替if/switch
int time = 2;
// 获取指定的Enum对象
State state = State.getInstance(time);
// 调用方法
int todayTime = state.getTodayTime();
state.sayHello();
System.out.println(todayTime);
// 正常调用枚举类的属性
System.out.println(State.FRIDAY);
}
}
参考
- https://snailclimb.gitee.io/javaguide/#/docs/java/basis/%E7%94%A8%E5%A5%BDJava%E4%B8%AD%E7%9A%84%E6%9E%9A%E4%B8%BE%E7%9C%9F%E7%9A%84%E6%B2%A1%E6%9C%89%E9%82%A3%E4%B9%88%E7%AE%80%E5%8D%95?id=_1%e6%a6%82%e8%a7%88
- https://blog.csdn.net/weixin_44437060/article/details/103800557
- https://www.jdon.com/51857
- https://blog.nowcoder.net/n/8f0280724e074093a7e7b5951098c2bc