• Java枚举基本使用,原理探究和扩展


    枚举类型的基本使用

    枚举类是和class一样的java关键字,用来定义枚举类的
    为什么定义的枚举类,可以单独定义和直接使用,不需要实例化?这需要探究它的内部原理

    定义和使用一个枚举

    public class enumdemos1 {
        public enum EnumDemo1 {
            A,B,C,D,E
        }
    
        public static void main(String[] args) {
            EnumDemo1 a = EnumDemo1.A;
            System.out.println(a);
            System.out.println(EnumDemo1.A);
            System.out.println(Arrays.asList(EnumDemo1.values()));
            System.out.println(EnumDemo1.valueOf(String.valueOf(EnumDemo1.B)));
            System.out.println(EnumDemo1.B.ordinal());
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    Enum类的常用方法

    values() 以数组形式返回枚举类型的所有成员
    valueOf() 将普通字符串转换为枚举实例
    compareTo() 比较两个枚举成员在定义时的顺序
    ordinal() 获取枚举成员的索引位置

    枚举的原理

    通过字节码看enum背后执行的操作

    public enum EnumDemo1 {
        A,
        B,
        C,
        D;
    
        private EnumDemo1() {
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    Compiled from "EnumDemo1.java"
    public final class src.Temun.EnumDemo1 extends java.lang.Enum<src.Temun.EnumDemo1> {
      public static final src.Temun.EnumDemo1 A;
    
      public static final src.Temun.EnumDemo1 B;
    
      public static final src.Temun.EnumDemo1 C;
    
      public static final src.Temun.EnumDemo1 D;
    
      public static src.Temun.EnumDemo1[] values();
        Code:
           0: getstatic     #1                  // Field $VALUES:[Lsrc/Temun/EnumDemo1;
           3: invokevirtual #2                  // Method "[Lsrc/Temun/EnumDemo1;".clone:()Ljava/lang/Object;
           6: checkcast     #3                  // class "[Lsrc/Temun/EnumDemo1;"
           9: areturn
    
      public static src.Temun.EnumDemo1 valueOf(java.lang.String);
        Code:
           0: ldc           #4                  // class src/Temun/EnumDemo1
           2: aload_0
           3: invokestatic  #5                  // Method java/lang/Enum.valueOf:(Ljava/lang/Class;Ljava/lang/String;)Ljava/lang/Enum;
           6: checkcast     #4                  // class src/Temun/EnumDemo1
           9: areturn
    
      static {};
        Code:
           0: new           #4                  // class src/Temun/EnumDemo1
           3: dup
           4: ldc           #7                  // String A
           6: iconst_0
           7: invokespecial #8                  // Method "":(Ljava/lang/String;I)V
          10: putstatic     #9                  // Field A:Lsrc/Temun/EnumDemo1;
          13: new           #4                  // class src/Temun/EnumDemo1
          16: dup
          17: ldc           #10                 // String B
          19: iconst_1
          20: invokespecial #8                  // Method "":(Ljava/lang/String;I)V
          23: putstatic     #11                 // Field B:Lsrc/Temun/EnumDemo1;
          26: new           #4                  // class src/Temun/EnumDemo1
          29: dup
          30: ldc           #12                 // String C
          32: iconst_2
          33: invokespecial #8                  // Method "":(Ljava/lang/String;I)V
          36: putstatic     #13                 // Field C:Lsrc/Temun/EnumDemo1;
          39: new           #4                  // class src/Temun/EnumDemo1
          42: dup
          43: ldc           #14                 // String D
          45: iconst_3
          46: invokespecial #8                  // Method "":(Ljava/lang/String;I)V
          49: putstatic     #15                 // Field D:Lsrc/Temun/EnumDemo1;
          52: iconst_4
          53: anewarray     #4                  // class src/Temun/EnumDemo1
          56: dup
          57: iconst_0
          58: getstatic     #9                  // Field A:Lsrc/Temun/EnumDemo1;
          61: aastore
          62: dup
          63: iconst_1
          64: getstatic     #11                 // Field B:Lsrc/Temun/EnumDemo1;
          67: aastore
          68: dup
          69: iconst_2
          70: getstatic     #13                 // Field C:Lsrc/Temun/EnumDemo1;
          73: aastore
          74: dup
          75: iconst_3
          76: getstatic     #15                 // Field D:Lsrc/Temun/EnumDemo1;
          79: aastore
          80: putstatic     #1                  // Field $VALUES:[Lsrc/Temun/EnumDemo1;
          83: return
    }
    
    
    • 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

    从字节码可以看出

    • enum最后被转为继承了extends java.lang.Enum的final不可以继承的类
    • enum生成的类的类名就是枚举类的类名
    • enum里定义的变量A,B,C,D都被实例化为了为了静态的枚举类对象,在static代码块里被初始化,

    总结:

    • 枚举类本质上也是一个普通的类,可以里面正常的定义方法和初始化函数等等

    • 而枚举类中定义的成员,比如上面代码里的A,B,C,D其实是这个枚举类实例化的静态对象

      • 因为是静态对象,所以可以直接获取到,又因为实例化了,所以可以调用枚举类内部自定义的方法。
      • 因为对象会被实例化,可以调用定义的初始化函数,而且会把enum类中定义的一些非静态方法转为对象的内部方法,对象在声明的时候也可以自定义自己专属方法
    • 枚举内部会自动生成两个静态的枚举方法(values,valueOf)

      • 枚举的静态方法数据类对象的,通过类直接调用

    枚举类就是一个普通的类,不同的是可以直接写几个值用来替代生成这个类的静态对象的过程,因此是一种定义类并在类中实例化静态对象的语法糖

    单例模式下使用枚举类型

    利用了枚举的对象是静态对象(准确的说应该是:类的静态字段),在jvm的类的静态变量初始化的时候使用了clinit()方法进行了初始化,这个方法是线程安全的

    class User {
        //私有化构造函数
        private User(){ }
    
        //定义一个静态枚举类
        static enum SingletonEnum{
            //创建一个枚举对象,该对象天生为单例
            INSTANCE;
            private User user;
            //私有化枚举的构造函数
            private SingletonEnum(){
                user=new User();
            }
            public User getInstnce(){
                return user;
            }
        }
    
        //对外暴露一个获取User对象的静态方法
        public static User getInstance(){
            return SingletonEnum.INSTANCE.getInstnce();
        }
    }
    
    public class Test {
        public static void main(String [] args){
            System.out.println(User.getInstance());
            System.out.println(User.getInstance());
            System.out.println(User.getInstance()==User.getInstance());
        }
    }
    
    • 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

    枚举集合EnumMap和EnumSet

    枚举集合和普通的集合相同,就是键值k为枚举类型罢了

    简单的例子,参考使用即可

    public static void main(String[] args) throws Exception {
            EnumMap<Season, String> map = new EnumMap<>(Season.class);
            map.put(Season.FALL, "硕果累累的秋天");
            map.put(Season.WINTER, "寒风凛冽的冬天");
            System.out.println(map.get(Season.FALL));
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
  • 相关阅读:
    C++ 重载运算符和重载函数
    C语言 实现链表的各种功能
    软件开发工具总结篇
    软设上午题-错题知识点一
    python循环时循环体一会多一会少,这个思路值得参考
    Windows 10 家庭中文版找不到Hyper-V功能解决方法100%解决
    【Redis】Bitmap 使用及应用场景
    猿创征文|vue组件之间的传值
    Cannot resolve plugin org.springframework.bootspring-boot-maven-plugin「unknown」
    构建全面预算体系,加强企业风险管理
  • 原文地址:https://blog.csdn.net/qq_37771209/article/details/126436318