作业16:java枚举类的秘密

  • JAVA代码
public enum EnumTest {
    HELLO,WORLD
}
  • 字节码
public final class EnumTest extends java.lang.Enum<EnumTest> {
  public static final EnumTest HELLO;

  public static final EnumTest WORLD;

  public static EnumTest[] values();
    Code:
       0: getstatic     #1                  // Field $VALUES:[LEnumTest;
       3: invokevirtual #2                  // Method "[LEnumTest;".clone:()Ljava/lang/Object;
       6: checkcast     #3                  // class "[LEnumTest;"
       9: areturn                           // 从当前方法返回对象引用

  // 调用了(EnumTest)java.lang.Enum.valueOf(EnumTest.class,String)
  public static EnumTest valueOf(java.lang.String);
    Code:
       0: ldc           #4                  // class EnumTest
       2: aload_0
       3: invokestatic  #5                  // Method java/lang/Enum.valueOf:(Ljava/lang/Class;Ljava/lang/String;)Ljava/lang/Enum;
       6: checkcast     #4                  // class EnumTest
       9: areturn

  static {};
    Code:
       0: new           #4                  // class EnumTest
       3: dup
       4: ldc           #7                  // String HELLO
       6: iconst_0
       7: invokespecial #8                  // Method "<init>":(Ljava/lang/String;I)V
      10: putstatic     #9                  // Field HELLO:LEnumTest;
      13: new           #4                  // class EnumTest
      16: dup
      17: ldc           #10                 // String WORLD
      19: iconst_1
      20: invokespecial #8                  // Method "<init>":(Ljava/lang/String;I)V
      23: putstatic     #11                 // Field WORLD:LEnumTest;
      26: iconst_2
      27: anewarray     #4                  // class EnumTest, 创建一个引用型(如类,接口,数组)的数组,并将其引用值压入栈顶
      30: dup
      31: iconst_0
      32: getstatic     #9                  // Field HELLO:LEnumTest;获取指定类的静态域,并将其值压入栈顶
      35: aastore
      36: dup
      37: iconst_1
      38: getstatic     #11                 // Field WORLD:LEnumTest;
      41: aastore
      42: putstatic     #1                  // Field $VALUES:[LEnumTest;用栈顶的值为指定的类的静态域赋值
      45: return
}
  • 参考源码实现的枚举(没有继承 java.lang.Enum):
public final class MyEnum {
    private final String s;

    private MyEnum(String s) {
        this.s = s;
    }

    public static final MyEnum HELLO = new MyEnum("HELLO");
    public static final MyEnum WORLD = new MyEnum("WORLD");

    private static volatile MyEnum[] $VALUES;

    static {
        Field[] fields = MyEnum.class.getFields();
        List<Field> list = Arrays.asList(fields);
        $VALUES = list.stream().map(field -> {
            try {
                return field.get(MyEnum.class);
            } catch (IllegalAccessException e) {
                e.printStackTrace();
                return null;
            }
        }).collect(Collectors.toList()).toArray(new MyEnum[fields.length]);
    }

    public static MyEnum[] values() {
        return $VALUES;
    }

    public static MyEnum valueOf(String name) throws NoSuchFieldException, IllegalAccessException {
        Class<MyEnum> clazz = MyEnum.class;
        Field field = clazz.getField(name);
        return (MyEnum) field.get(clazz);
    }

    @Override
    public String toString() {
        return s;
    }
}
  • java.lang.Enum类
// Enum 不能直接被继承
// 下列省略部分代码
public abstract class Enum<E extends Enum<E>>
        implements Comparable<E>, Serializable {
   
    private final String name;
    
    private final int ordinal;

    public final String name() {
        return name;
    }

    public final int ordinal() {
        return ordinal;
    }

    protected Enum(String name, int ordinal) {
        this.name = name;
        this.ordinal = ordinal;
    }

    public String toString() {
        return name;
    }
	
	// 比较ordinal值,用于排序
    public final int compareTo(E o) {
        Enum<?> other = (Enum<?>)o;
        Enum<E> self = this;
        if (self.getClass() != other.getClass() && // optimization
            self.getDeclaringClass() != other.getDeclaringClass())
            throw new ClassCastException();
        return self.ordinal - other.ordinal;
    }

    @SuppressWarnings("unchecked")
    public final Class<E> getDeclaringClass() {
        Class<?> clazz = getClass(); // 获取当前类的Class
        Class<?> zuper = clazz.getSuperclass(); // 获取当前类的父类
        // 如果父类是Enum.class,则返回当前类的Class,否则返回父类的Class
        return (zuper == Enum.class) ? (Class<E>)clazz : (Class<E>)zuper;
    }

    public static <T extends Enum<T>> T valueOf(Class<T> enumType,String name) {
        T result = enumType.enumConstantDirectory().get(name);
        if (result != null) return result;
        // 为什么不先判断name是否等于null?
        if (name == null) throw new NullPointerException("Name is null");
        throw new IllegalArgumentException("No enum constant " + enumType.getCanonicalName() + "." + name);
    }

    public final boolean equals(Object var1) {
        return this == var1;
    }
}

public final class Class<T>{
	 
	 private transient volatile Map<String, T> enumConstantDirectory;
	 
	 // 简单的说生成枚举Map:{"HEELO":EnumTest.HELLO,"WORLD":EnumTest.WORLD}	 
	 Map<String, T> enumConstantDirectory() {
        Map<String, T> directory = enumConstantDirectory;
        if (directory == null) {
            T[] universe = getEnumConstantsShared();
            if (universe == null)
                throw new IllegalArgumentException(getName() + " is not an enum type");
            directory = new HashMap<>(2 * universe.length);
            for (T constant : universe) {
                directory.put(((Enum<?>)constant).name(), constant);
            }
            enumConstantDirectory = directory;
        }
        return directory;
    }
    
    private transient volatile T[] enumConstants;
    
    T[] getEnumConstantsShared() {
        T[] constants = enumConstants;
        if (constants == null) {
        	// 非Enum 直接返回null
            if (!isEnum()) return null;
            try {
                final Method values = getMethod("values");
                // 提升访问修饰
                java.security.AccessController.doPrivileged(
                    new java.security.PrivilegedAction<>() {
                        public Void run() {
                                values.setAccessible(true);
                                return null;
                            }
                        });
                // 反射调用values方法,得到枚举数组
                @SuppressWarnings("unchecked")
                T[] temporaryConstants = (T[])values.invoke(null);
                enumConstants = constants = temporaryConstants;
            }catch (InvocationTargetException | NoSuchMethodException |IllegalAccessException ex) { 
                return null; 
            }
        }
        return constants;
    }
    
    public boolean isEnum() {
    	// 返回此类或接口以整数编码的 Java语言修饰符,如:public private protected、enum等。
    	// 如果modifers有enum修饰语ENUM &操作将得到ENUM,不等于0。
        return (this.getModifiers() & ENUM) != 0 &&
        this.getSuperclass() == java.lang.Enum.class;
    }
}
  • 测试
Class<?> aClass = EnumTest.HELLO.getClass();
System.out.println(aClass); // class EnumTest
System.out.println(aClass.getSuperclass()); // class java.lang.Enum
  • 结论
    • 枚举类是一个普通的java类,enum类型只是java的语法糖,编译器帮助开发人员转化为Eunm类。
    • 枚举类继承了java.lang.Enum类,valueOf和values方法继承自Enum类。
    • java.lang.Enum类不能被直接继承,所以自己实现的valueOf的实现采用了反射获取字段。
    • java.lang.Enum类的valueOf实现采用了Class类反射和内部的map缓存。
posted @ 2018-09-18 10:41  月下小魔王  阅读(325)  评论(0编辑  收藏  举报