java枚举类型(enum)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/u012998254/article/details/82707510

枚举实现原理

package com.own.learn.jdk.enum1;



public enum Day {
    MONDAY("monday"), TUESDAY("TUESDAY"), WEDNESDAY("WEDNESDAY"),
    THURSDAY("THURSDAY"), FRIDAY("FRIDAY"), SATURDAY("SATURDAY"), SUNDAY("SUNDAY");

    private String name;

    Day(String name) {
        this.name = name;
    }
}

拿出来反编译的代码:

javap -c com/own/learn/jdk/enum1/Day.class

public final class com.own.learn.jdk.enum1.Day extends java.lang.Enum<com.own.learn.jdk.enum1.Day> {
  public static final com.own.learn.jdk.enum1.Day MONDAY;

  public static final com.own.learn.jdk.enum1.Day TUESDAY;

  public static final com.own.learn.jdk.enum1.Day WEDNESDAY;

  public static final com.own.learn.jdk.enum1.Day THURSDAY;

  public static final com.own.learn.jdk.enum1.Day FRIDAY;

  public static final com.own.learn.jdk.enum1.Day SATURDAY;

  public static final com.own.learn.jdk.enum1.Day SUNDAY;

  public static com.own.learn.jdk.enum1.Day[] values();
    Code:
       0: getstatic     #1                  // Field $VALUES:[Lcom/own/learn/jdk/enum1/Day;
       3: invokevirtual #2                  // Method "[Lcom/own/learn/jdk/enum1/Day;".clone:()Ljava/lang/Object;
       6: checkcast     #3                  // class "[Lcom/own/learn/jdk/enum1/Day;"
       9: areturn

  public static com.own.learn.jdk.enum1.Day valueOf(java.lang.String);
    Code:
       0: ldc           #4                  // class com/own/learn/jdk/enum1/Day
       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/own/learn/jdk/enum1/Day
       9: areturn

  static {};
    Code:
       0: new           #4                  // class com/own/learn/jdk/enum1/Day
       3: dup
       4: ldc           #8                  // String MONDAY
       6: iconst_0
       7: ldc           #9                  // String monday
       9: invokespecial #10                 // Method "<init>":(Ljava/lang/String;ILjava/lang/String;)V
      12: putstatic     #11                 // Field MONDAY:Lcom/own/learn/jdk/enum1/Day;
      15: new           #4                  // class com/own/learn/jdk/enum1/Day
      18: dup
      19: ldc           #12                 // String TUESDAY
      21: iconst_1
      22: ldc           #12                 // String TUESDAY
      24: invokespecial #10                 // Method "<init>":(Ljava/lang/String;ILjava/lang/String;)V
      27: putstatic     #13                 // Field TUESDAY:Lcom/own/learn/jdk/enum1/Day;
      30: new           #4                  // class com/own/learn/jdk/enum1/Day
      33: dup
      34: ldc           #14                 // String WEDNESDAY
      36: iconst_2
      37: ldc           #14                 // String WEDNESDAY
      39: invokespecial #10                 // Method "<init>":(Ljava/lang/String;ILjava/lang/String;)V
      42: putstatic     #15                 // Field WEDNESDAY:Lcom/own/learn/jdk/enum1/Day;
      45: new           #4                  // class com/own/learn/jdk/enum1/Day
      48: dup
      49: ldc           #16                 // String THURSDAY
      51: iconst_3
      52: ldc           #16                 // String THURSDAY
      54: invokespecial #10                 // Method "<init>":(Ljava/lang/String;ILjava/lang/String;)V
      57: putstatic     #17                 // Field THURSDAY:Lcom/own/learn/jdk/enum1/Day;
      60: new           #4                  // class com/own/learn/jdk/enum1/Day
      63: dup
      64: ldc           #18                 // String FRIDAY
      66: iconst_4
      67: ldc           #18                 // String FRIDAY
      69: invokespecial #10                 // Method "<init>":(Ljava/lang/String;ILjava/lang/String;)V
      72: putstatic     #19                 // Field FRIDAY:Lcom/own/learn/jdk/enum1/Day;
      75: new           #4                  // class com/own/learn/jdk/enum1/Day
      78: dup
      79: ldc           #20                 // String SATURDAY
      81: iconst_5
      82: ldc           #20                 // String SATURDAY
      84: invokespecial #10                 // Method "<init>":(Ljava/lang/String;ILjava/lang/String;)V
      87: putstatic     #21                 // Field SATURDAY:Lcom/own/learn/jdk/enum1/Day;
      90: new           #4                  // class com/own/learn/jdk/enum1/Day
      93: dup
      94: ldc           #22                 // String SUNDAY
      96: bipush        6
      98: ldc           #22                 // String SUNDAY
     100: invokespecial #10                 // Method "<init>":(Ljava/lang/String;ILjava/lang/String;)V
     103: putstatic     #23                 // Field SUNDAY:Lcom/own/learn/jdk/enum1/Day;
     106: bipush        7
     108: anewarray     #4                  // class com/own/learn/jdk/enum1/Day
     111: dup
     112: iconst_0
     113: getstatic     #11                 // Field MONDAY:Lcom/own/learn/jdk/enum1/Day;
     116: aastore
     117: dup
     118: iconst_1
     119: getstatic     #13                 // Field TUESDAY:Lcom/own/learn/jdk/enum1/Day;
     122: aastore
     123: dup
     124: iconst_2
     125: getstatic     #15                 // Field WEDNESDAY:Lcom/own/learn/jdk/enum1/Day;
     128: aastore
     129: dup
     130: iconst_3
     131: getstatic     #17                 // Field THURSDAY:Lcom/own/learn/jdk/enum1/Day;
     134: aastore
     135: dup
     136: iconst_4
     137: getstatic     #19                 // Field FRIDAY:Lcom/own/learn/jdk/enum1/Day;
     140: aastore
     141: dup
     142: iconst_5
     143: getstatic     #21                 // Field SATURDAY:Lcom/own/learn/jdk/enum1/Day;
     146: aastore
     147: dup
     148: bipush        6
     150: getstatic     #23                 // Field SUNDAY:Lcom/own/learn/jdk/enum1/Day;
     153: aastore
     154: putstatic     #1                  // Field $VALUES:[Lcom/own/learn/jdk/enum1/Day;
     157: return
}

转换成代码 大概是这样的:

package com.own.learn.jdk.enum1;

public final class DayEnum extends Enum {
    public static DayEnum MONDAY;

    public static DayEnum TUESDAY;

    public static DayEnum WEDNESDAY;

    public static DayEnum THURSDAY;

    public static DayEnum FRIDAY;

    public static DayEnum SATURDAY;

    public static DayEnum SUNDAY;
    private static DayEnum $VALUES[];

    static {
        MONDAY = new DayEnum("MONDAY", 0);
        TUESDAY = new DayEnum("TUESDAY", 1);
        WEDNESDAY = new DayEnum("WEDNESDAY", 2);
        THURSDAY = new DayEnum("THURSDAY", 3);
        FRIDAY = new DayEnum("FRIDAY", 4);
        SATURDAY = new DayEnum("SATURDAY", 5);
        SUNDAY = new DayEnum("SUNDAY", 6);
        $VALUES = (new DayEnum[]{
                MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY
        });
    }


    public DayEnum[] values() {
        return (DayEnum[]) $VALUES.clone();
    }

    public DayEnum valueOf(String name) {
        return (DayEnum) Enum.valueOf(com.own.learn.jdk.enum1.DayEnum.class, name);

    }

    protected DayEnum(String name, int ordinal) {
        super(name, ordinal);
    }

    @Override
    public String toString() {
        return super.toString();
    }
}

Enum类

public abstract class Enum<E extends Enum<E>>
        implements Comparable<E>, Serializable {

    private final String name;


    public final String name() {
        return name;
    }


    private final int ordinal;


    public final int ordinal() {
        return ordinal;
    }


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


    public String toString() {
        return name;
    }


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


    public final int hashCode() {
        return super.hashCode();
    }


    protected final Object clone() throws CloneNotSupportedException {
        throw new CloneNotSupportedException();
    }


    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<?> zuper = clazz.getSuperclass();
        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;
        if (name == null)
            throw new NullPointerException("Name is null");
        throw new IllegalArgumentException(
                "No enum constant " + enumType.getCanonicalName() + "." + name);
    }

    /**
     * enum classes cannot have finalize methods.
     */
    protected final void finalize() {
    }


    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");
    }
}
  1. ordinal: 从0到Integer.Max_value的数字,只在EnumSet和EnumMap使用,默认是0.
  2. equals方法:`return this==other。枚举是常量
  3. compareTo:默认比较的是:ordinal
  4. valueOf:enumType.enumConstantDirectory().get(name);
  Map<String, T> enumConstantDirectory() {
        if (enumConstantDirectory == null) {
            T[] universe = getEnumConstantsShared();
            if (universe == null)
                throw new IllegalArgumentException(
                    getName() + " is not an enum type");
            Map<String, T> m = new HashMap<>(2 * universe.length);
            for (T constant : universe)
                m.put(((Enum<?>)constant).name(), constant);
            enumConstantDirectory = m;
        }
        return enumConstantDirectory;
    }
 T[] getEnumConstantsShared() {
        if (enumConstants == null) {
            if (!isEnum()) return null;
            try {
                final Method values = getMethod("values");
                java.security.AccessController.doPrivileged(
                    new java.security.PrivilegedAction<Void>() {
                        public Void run() {
                                values.setAccessible(true);
                                return null;
                            }
                        });
                @SuppressWarnings("unchecked")
                T[] temporaryConstants = (T[])values.invoke(null);
                enumConstants = temporaryConstants;
            }
            // These can happen when users concoct enum-like classes
            // that don't comply with the enum spec.
            catch (InvocationTargetException | NoSuchMethodException |
                   IllegalAccessException ex) { return null; }
        }
        return enumConstants;
    }
    private volatile transient T[] enumConstants = null;

通过反射调用values方法得到枚举的数组,然后转成map

枚举的进阶用法

向enum类添加方法与自定义构造函数

public enum Day {
    MONDAY("monday"), TUESDAY("TUESDAY"), WEDNESDAY("WEDNESDAY"),
    THURSDAY("THURSDAY"), FRIDAY("FRIDAY"), SATURDAY("SATURDAY"), SUNDAY("SUNDAY");

    private String name;

    Day(String name) {
        this.name = name;
    }
}

enum类中定义抽象方法

package com.own.learn.jdk.enum1;

public enum  DayAbstractMethod {

    FOOD {
        @Override
        public void printName() {
            System.out.println(" name is " + name());
        }
    };

    public abstract void printName();


    public static void main(String[] args) {

        DayAbstractMethod.FOOD.printName();
    }
}

enum类与接口

package com.own.learn.jdk.enum1;

interface Start{
    void start();
}

interface End{
    void end();
}
public enum  EnumInterface implements Start, End{
    TEST1
    ;


    @Override
    public void start() {

    }

    @Override
    public void end() {

    }
}

与单例模式

public enum  EnumSingleton {

     private enum MyEnumSingleton{
        INSTANCE;
        private Resource resource;

        private MyEnumSingleton(){
            resource = new Resource();
        }

        public Resource getResource(){
            return resource;
        }
    }

    public static Resource getResource(){
        return MyEnumSingleton.INSTANCE.getResource();
    }

}

多线程环境下的安全性

这个特性上面已经介绍了,因为INSTANCE最后会被编译器处理成static final的,并且在static模块中进行的初始化,因此它的实例化是在class被加载阶段完成,是线程安全的。这个特性也决定了枚举单例不是lazy的,如果你的单例初始化比较费时且大多数情况下只会被引用但是不会被真正调用的话,你需要使用lazy的单例模式(上面传统单例的方法二实现),而不要选择枚举单例。

不可被反射实例化

在Java中,不仅通过限制enum只能声明private的构造方法来防止Enum被使用new进行实例化,而且还限制了使用反射的方法不能通过Constructor来newInstance一个枚举实例。

序列化的唯一性

在序列化和反序列化的时候Enum的处理是和其他类不同的,在序列化的时候实际上只写入了Enum的name成员,而没有保存ordinal成员;在反序列化的时候从ObjectInputStream中读取Enum的name成员,同时调用Enum的valueof方法传入读取的name得到对应的ordinal值。同时Enum是不支持自定义序列化和反序列化的,一些序列化和反序列化对应的函数例如readObject和writeObject及serialVersionUID等属性在Enum的序列化过程中都是被忽略的。
Enum在序列化和反序列化上的特性保证了使用Enum来实现单例是经受得起序列化的攻击的。

Java枚举单例

猜你喜欢

转载自blog.csdn.net/u012998254/article/details/82707510