zoukankan      html  css  js  c++  java
  • 作业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缓存。
  • 相关阅读:
    图解VS2008单元测试及查看代码覆盖率
    Effective C++:条款02:尽量以const, enum, inline替换#define (Prefer consts, enums, and inline to #defines.)
    Effective C++:条款01:视C++为一个语言联邦(View C++ as a federation of languages.)
    Effective C++:条款03:尽可能使用const (Use const whenever possible.)
    mysql foreign key <转>
    Linux下Apache绑定多个域名的方法 <转>
    python(1)input()和raw_input
    《精通CSS》读书笔记(1)
    CSS相对定位和绝对定位
    【分享】沪江网提供的每日一句API
  • 原文地址:https://www.cnblogs.com/linzhanfly/p/9667538.html
Copyright © 2011-2022 走看看