美文网首页
关于Enum

关于Enum

作者: 袁小象 | 来源:发表于2019-04-10 21:34 被阅读0次

    说明

    声明一个枚举其实很简单,直接利用enum关键字即可,像声明一个class一样:

    public enum Season {
        SPRING("Spring"),
        SUMMER("Summer"),
        AUTUMN("Autumn"),
        WINTER("Winter");
    
        private String description;
    
        Season(String desc) {
            this.description = desc;
        }
    
        public String getDescription() {
            return description;
        }
    }
    

    使用枚举有很多的好处,它避免了传统常量的无范围性,而且我们可以利用枚举实现单例模式。其实,enum只是一个语法糖,我们使用它声明一个枚举类型, 其余事情就是 Java 编译器帮我们干的了。
    使用javac编译成class文件,再利用javap -c将其反编译出来,得到

    public final class com.yuanqixiang.service.enums.Season extends java.lang.Enum<com.yuanqixiang.service.enums.Season> {
      public static final com.yuanqixiang.service.enums.Season SPRING;
    
      public static final com.yuanqixiang.service.enums.Season SUMMER;
    
      public static final com.yuanqixiang.service.enums.Season AUTUMN;
    
      public static final com.yuanqixiang.service.enums.Season WINTER;
    
      public static com.yuanqixiang.service.enums.Season[] values();
        Code:
           0: getstatic     #1                  // Field $VALUES:[Lcom/yuanqixiang/service/enums/Season;
           3: invokevirtual #2                  // Method "[Lcom/yuanqixiang/service/enums/Season;".clone:()Ljava/lang/Object;
           6: checkcast     #3                  // class "[Lcom/yuanqixiang/service/enums/Season;"
           9: areturn
    
      public static com.yuanqixiang.service.enums.Season valueOf(java.lang.String);
        Code:
           0: ldc           #4                  // class com/yuanqixiang/service/enums/Season
           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/yuanqixiang/service/enums/Season
           9: areturn
    
      public java.lang.String getDescription();
        Code:
           0: aload_0
           1: getfield      #7                  // Field description:Ljava/lang/String;
           4: areturn
    
      static {};
        Code:
           0: new           #4                  // class com/yuanqixiang/service/enums/Season
           3: dup
           4: ldc           #8                  // String SPRING
           6: iconst_0
           7: ldc           #9                  // String Spring
           9: invokespecial #10                 // Method "<init>":(Ljava/lang/String;ILjava/lang/String;)V
          12: putstatic     #11                 // Field SPRING:Lcom/yuanqixiang/service/enums/Season;
          15: new           #4                  // class com/yuanqixiang/service/enums/Season
          18: dup
          19: ldc           #12                 // String SUMMER
          21: iconst_1
          22: ldc           #13                 // String Summer
          24: invokespecial #10                 // Method "<init>":(Ljava/lang/String;ILjava/lang/String;)V
          27: putstatic     #14                 // Field SUMMER:Lcom/yuanqixiang/service/enums/Season;
          30: new           #4                  // class com/yuanqixiang/service/enums/Season
          33: dup
          34: ldc           #15                 // String AUTUMN
          36: iconst_2
          37: ldc           #16                 // String Autumn
          39: invokespecial #10                 // Method "<init>":(Ljava/lang/String;ILjava/lang/String;)V
          42: putstatic     #17                 // Field AUTUMN:Lcom/yuanqixiang/service/enums/Season;
          45: new           #4                  // class com/yuanqixiang/service/enums/Season
          48: dup
          49: ldc           #18                 // String WINTER
          51: iconst_3
          52: ldc           #19                 // String Winter
          54: invokespecial #10                 // Method "<init>":(Ljava/lang/String;ILjava/lang/String;)V
          57: putstatic     #20                 // Field WINTER:Lcom/yuanqixiang/service/enums/Season;
          60: iconst_4
          61: anewarray     #4                  // class com/yuanqixiang/service/enums/Season
          64: dup
          65: iconst_0
          66: getstatic     #11                 // Field SPRING:Lcom/yuanqixiang/service/enums/Season;
          69: aastore
          70: dup
          71: iconst_1
          72: getstatic     #14                 // Field SUMMER:Lcom/yuanqixiang/service/enums/Season;
          75: aastore
          76: dup
          77: iconst_2
          78: getstatic     #17                 // Field AUTUMN:Lcom/yuanqixiang/service/enums/Season;
          81: aastore
          82: dup
          83: iconst_3
          84: getstatic     #20                 // Field WINTER:Lcom/yuanqixiang/service/enums/Season;
          87: aastore
          88: putstatic     #1                  // Field $VALUES:[Lcom/yuanqixiang/service/enums/Season;
          91: return
    }
    
    

    从上面的代码可以看出:
    1、定义的Season是一个final类型的类,继承自java.lang.Enum
    2、声明了字段对应的四个 static final Season 的实例
    3、实现了 values()valueOf(String)静态方法
    4、static{ ... } 对所有成员进行初始化

    根据以上的字节码,我们可以大致还原出Season类的原貌:

    public final class Season extends java.lang.Enum<Season> {
     
      public static final Season SPRING;
      public static final Season SUMMER;
      public static final Season AUTUMN;
      public static final Season WINTER;
     
      private static final Season[] $VALUES;
     
      private String description;
      static {
        SPRING = new Season("Spring", "SPRING", 0);
        SUMMER = new Season("Summer", "SUMMER", 1);
        AUTUMN = new Season("Autumn", "AUTUMN", 2);
        WINTER = new Season("Winter", "WINTER", 3);
     
        $VALUES = new Season[] {SPRING, SUMMER, AUTUMN, WINTER};
      }
     
      private Season(String desc, String name, int original) {
        this.description = desc;
        super(name, original)
      }
     
      public static Season[] values() {
        return $VALUE.clone();
      }
     
      public static Season valueOf(String name) {
        return Enum.valueOf(Season.class, name);
      }
    }
    

    上面的代码并不是最正确的代码,只是经过java字节码推敲出来的。

    了解JVM的类加载机制的朋友应该对这部分比较清楚。static类型的属性会在类被加载之后被初始化,当一个Java类第一次被真正使用到的时候静态资源被初始化,Java类的加载和初始化过程都是线程安全的(因为虚拟机在加载枚举的类的时候,会使用ClassLoader的loadClass方法,而这个方法使用同步代码块保证了线程安全)。所以,创建一个enum类型是线程安全的。

    也就是说,我们定义的一个枚举,在第一次被真正用到的时候,会被虚拟机加载并初始化,而这个初始化过程是线程安全的。而我们知道,解决单例的并发问题,主要解决的就是初始化过程中的线程安全问题。

    所以,由于枚举的以上特性,枚举实现的单例是天生线程安全的。

    相关文章

      网友评论

          本文标题:关于Enum

          本文链接:https://www.haomeiwen.com/subject/qdpniqtx.html