• Java基础之细说枚举


    枚举类(Enum)

    当我们使用关键字 enum 创建一个枚举时,他具有如下特性

    特点

    • 构造器是私有的
    • 是一个类,默认继承 Enum,并且使用 final 修饰,可以有自己的成员变量,成员方法,静态方法、静态变量等

    示例

    无参数的枚举

    enum  HTTP_STATUS{
        OK,     //是一个HTTP_STATUS枚举类型 
        NOT_FOUND
    }
    
    • 1
    • 2
    • 3
    • 4

    编译后的代码

    enum HTTP_STATUS {
        OK,
        NOT_FOUND;
        
    	//默认生成私有无参构造器
        private HTTP_STATUS() {
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    有参数的枚举

    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;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    查看字节码

    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  
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116

    通过汇编指令,发现了枚举类型除了我们自己定义的方法外,还有如下方法

    //获取所有的枚举类型
    HTTP_STATUS[] values()   
    
    //根据枚举名称获取对应的枚举类型
    HTTP_STATUS valueOf(java.lang.String);
    
    • 1
    • 2
    • 3
    • 4
    • 5

    此外,默认是继承了 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("can't deserialize enum");
        }
    
        private void readObjectNoData() throws ObjectStreamException {
            throw new InvalidObjectException("can't 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();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28

    为什么说枚举创建单例是安全的

    枚举类型的成员变量是 static final 修饰的,在类加载阶段就已经被被赋值了,而类加载阶段是线程安全的

    现在我们想一个办法创建一个对象来破环枚举单例,我们知道的有如下方法

    • Java关键字new,但是枚举类型的构造器是私有的(private
    • 通过反射,但是反射也是依赖于构造器
    • 反序列化,因为枚举类型继承了Enum,但是Enum的 readObject 方法直接抛异常
    • 通过 clone 方法,因为枚举类型继承了Enum,但是Enum的 clone 方法被 final 修饰 ,而且方法直接抛异常

    综上,使用枚举创建单例是线程安全的

  • 相关阅读:
    设备通信盒更新硬件和软件后,无法控制床
    Maixll-Dock 使用方法
    JVM垃圾回收
    二百零二、Hive——Hive解析JSON字段(单个字段与json数组)
    halcon脚本-边缘及骨架的识别【附源码】
    WZOI-256奇怪的数列
    Uni-App常用事件
    numpy的使用教程
    【RSocket】使用 RSocket (一)——建立连接
    LinkedHashMap
  • 原文地址:https://blog.csdn.net/qq_42224683/article/details/125475107