Java基础之细说枚举
Posted 罗罗的1024
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java基础之细说枚举相关的知识,希望对你有一定的参考价值。
枚举类(Enum)
当我们使用关键字 enum
创建一个枚举时,他具有如下特性
特点
- 构造器是私有的
- 是一个类,默认继承
Enum
,并且使用final
修饰,可以有自己的成员变量,成员方法,静态方法、静态变量等
示例
无参数的枚举
enum HTTP_STATUS
OK, //是一个HTTP_STATUS枚举类型
NOT_FOUND
编译后的代码
enum HTTP_STATUS
OK,
NOT_FOUND;
//默认生成私有无参构造器
private HTTP_STATUS()
有参数的枚举
enum HTTP_STATUS
OK(200,"请求成功"),
NOT_FOUND(404,"无法找到资源");
private Integer code;
private String value;
private HTTP_STATUS(int code, String value)
this.code = code;
this.value = value;
public Integer getCode()
return code;
public String getValue()
return value;
查看字节码
Classfile /D:/question/questions/target/classes/com/tq/questions/HTTP_STATUS.class
Last modified 2022-6-25; size 1758 bytes
MD5 checksum f38e7c76916dd6c0f40f3c055dbf8e19
Compiled from "Test.java"
//继承Enum,final修饰
final class com.tq.questions.HTTP_STATUS extends java.lang.Enum<com.tq.questions.HTTP_STATUS>
minor version: 0
major version: 52
flags: ACC_FINAL, ACC_SUPER, ACC_ENUM
...........
//每一个枚举类型都是static final 修饰的
public static final com.tq.questions.HTTP_STATUS OK;
descriptor: Lcom/tq/questions/HTTP_STATUS;
flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL, ACC_ENUM
public static final com.tq.questions.HTTP_STATUS NOT_FOUND;
descriptor: Lcom/tq/questions/HTTP_STATUS;
flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL, ACC_ENUM
public static com.tq.questions.HTTP_STATUS[] values();
descriptor: ()[Lcom/tq/questions/HTTP_STATUS;
flags: ACC_PUBLIC, ACC_STATIC
Code:
stack=1, locals=0, args_size=0
0: getstatic #1 // Field $VALUES:[Lcom/tq/questions/HTTP_STATUS;
3: invokevirtual #2 // Method "[Lcom/tq/questions/HTTP_STATUS;".clone:()Ljava/lang/Object;
6: checkcast #3 // class "[Lcom/tq/questions/HTTP_STATUS;"
9: areturn
LineNumberTable:
line 20: 0
public static com.tq.questions.HTTP_STATUS valueOf(java.lang.String);
descriptor: (Ljava/lang/String;)Lcom/tq/questions/HTTP_STATUS;
flags: ACC_PUBLIC, ACC_STATIC
Code:
stack=2, locals=1, args_size=1
0: ldc #4 // class com/tq/questions/HTTP_STATUS
2: aload_0
3: invokestatic #5 // Method java/lang/Enum.valueOf:(Ljava/lang/Class;Ljava/lang/String;)Ljava/lang/Enum;
6: checkcast #4 // class com/tq/questions/HTTP_STATUS
9: areturn
LineNumberTable:
line 20: 0
LocalVariableTable:
Start Length Slot Name Signature
0 10 0 name Ljava/lang/String;
public java.lang.Integer getCode();
descriptor: ()Ljava/lang/Integer;
flags: ACC_PUBLIC
Code:
stack=1, locals=1, args_size=1
0: aload_0
1: getfield #8 // Field code:Ljava/lang/Integer;
4: areturn
LineNumberTable:
line 34: 0
LocalVariableTable:
Start Length Slot Name Signature
0 5 0 this Lcom/tq/questions/HTTP_STATUS;
public java.lang.String getValue();
descriptor: ()Ljava/lang/String;
flags: ACC_PUBLIC
Code:
stack=1, locals=1, args_size=1
0: aload_0
1: getfield #9 // Field value:Ljava/lang/String;
4: areturn
LineNumberTable:
line 38: 0
LocalVariableTable:
Start Length Slot Name Signature
0 5 0 this Lcom/tq/questions/HTTP_STATUS;
static ;
descriptor: ()V
flags: ACC_STATIC
Code:
stack=7, locals=0, args_size=0
0: new #4 // class com/tq/questions/HTTP_STATUS
3: dup
4: ldc #11 // String OK
6: iconst_0
7: sipush 200
10: ldc #12 // String 请求成功
12: ldc #13 // String
14: invokespecial #14 // Method "<init>":(Ljava/lang/String;IILjava/lang/String;Ljava/lang/String;)V
17: putstatic #15 // Field OK:Lcom/tq/questions/HTTP_STATUS;
20: new #4 // class com/tq/questions/HTTP_STATUS
23: dup
24: ldc #16 // String NOT_FOUND
26: iconst_1
27: sipush 404
30: ldc #17 // String 无法找到资源
32: ldc #13 // String
34: invokespecial #14 // Method "<init>":(Ljava/lang/String;IILjava/lang/String;Ljava/lang/String;)V
37: putstatic #18 // Field NOT_FOUND:Lcom/tq/questions/HTTP_STATUS;
40: iconst_2
41: anewarray #4 // class com/tq/questions/HTTP_STATUS
44: dup
45: iconst_0
46: getstatic #15 // Field OK:Lcom/tq/questions/HTTP_STATUS;
49: aastore
50: dup
51: iconst_1
52: getstatic #18 // Field NOT_FOUND:Lcom/tq/questions/HTTP_STATUS;
55: aastore
56: putstatic #1 // Field $VALUES:[Lcom/tq/questions/HTTP_STATUS;
59: return
LineNumberTable:
line 4: 0
line 5: 20
line 3: 40
通过汇编指令,发现了枚举类型除了我们自己定义的方法外,还有如下方法
//获取所有的枚举类型
HTTP_STATUS[] values()
//根据枚举名称获取对应的枚举类型
HTTP_STATUS valueOf(java.lang.String);
此外,默认是继承了 Enum 类型,并且用 final 修饰
public abstract class Enum<E extends Enum<E>> implements Comparable<E>, Serializable
.................
/**
* prevent default deserialization
* 反序列化直接抛异常
*/
private void readObject(ObjectInputStream in) throws IOException,
ClassNotFoundException
throw new InvalidObjectException("cant deserialize enum");
private void readObjectNoData() throws ObjectStreamException
throw new InvalidObjectException("cant deserialize enum");
/**
* Throws CloneNotSupportedException. This guarantees that enums
* are never cloned, which is necessary to preserve their "singleton"
* status.
*
* @return (never returns)
*/
protected final Object clone() throws CloneNotSupportedException
throw new CloneNotSupportedException();
为什么说枚举创建单例是安全的
枚举类型的成员变量是 static final
修饰的,在类加载阶段就已经被被赋值了,而类加载阶段是线程安全的
现在我们想一个办法创建一个对象来破环枚举单例,我们知道的有如下方法
- Java关键字new,但是枚举类型的构造器是私有的(
private
) - 通过反射,但是反射也是依赖于构造器
- 反序列化,因为枚举类型继承了Enum,但是Enum的
readObject
方法直接抛异常 - 通过 clone 方法,因为枚举类型继承了Enum,但是Enum的
clone
方法被final
修饰 ,而且方法直接抛异常
综上,使用枚举创建单例是线程安全的
以上是关于Java基础之细说枚举的主要内容,如果未能解决你的问题,请参考以下文章