java 枚举 Enum 详解

1、反遍Yi枚举类

1.1 举例1:普通枚举类

enum代码:

public enum ColorEnum {
  RED,
  BLACK,
  BLUE;

  ColorEnum() {
  }
}

jad下载

编Yi并反编Yi:
在这里插入图片描述
反编Yi后的代码:

多了values(),valueOf(String s)方法

// Decompiled by Jad v1.5.8g. Copyright 2001 Pavel Kouznetsov.
// Jad home page: http://www.kpdus.com/jad.html
// Decompiler options: packimports(3) 
// Source File Name:   ColorEnum.java

//final类,不能被继承;继承了抽象类Enum,不能再继承别的类
public final class ColorEnum extends Enum
{

	//得到枚举常量集合
    public static ColorEnum[] values()
    {
        return (ColorEnum[])$VALUES.clone();
    }

	//根据s得到对Ying的枚举常量
    public static ColorEnum valueOf(String s)
    {
        return (ColorEnum)Enum.valueOf(ColorEnum, s);
    }

	//私You的构造函数
    private ColorEnum(String s, int i)
    {
        super(s, i);
    }

	//枚举常量被解析成static final属性
    public static final ColorEnum RED;
    public static final ColorEnum BLACK;
    public static final ColorEnum BLUE;
    
    private static final ColorEnum $VALUES[];

	//静态代码块:在clinit方法执行的时候,执行
    static 
    {
        RED = new ColorEnum("RED", 0);
        BLACK = new ColorEnum("BLACK", 1);
        BLUE = new ColorEnum("BLUE", 2);
        $VALUES = (new ColorEnum[] {
            RED, BLACK, BLUE
        });
    }
}

1.2 举例1:带 属性的 枚举类

枚举类除了能带属性外,还能带方法等,和普通类类似。

enum代码:

public enum OperateEnum {
  ADD("add", 1),
  SUBTRACT("subtract", 2),
  MULTIPLY("multiply", 3),
  DIVIDE("divide", 4);

  private String name;
  private int index;

  OperateEnum(String name, int index) {
    this.name = name;
    this.index = index;
  }

  public String getName() {
    return name;
  }

  public void setName(String name) {
    this.name = name;
  }

  public int getIndex() {
    return index;
  }

  public void setIndex(int index) {
    this.index = index;
  }
}

jad下载

编Yi并反编Yi:
在这里插入图片描述
反编Yi后的代码:

// Decompiled by Jad v1.5.8g. Copyright 2001 Pavel Kouznetsov.
// Jad home page: http://www.kpdus.com/jad.html
// Decompiler options: packimports(3) 
// Source File Name:   OperateEnum.java

//final类,不能被继承;该类继承自抽象类Enum,不能在继承别的类
public final class OperateEnum extends Enum
{

    //得到枚举值集合
    public static OperateEnum[] values()
    {
        return (OperateEnum[])$VALUES.clone();
    }
    
    //根据s找到对Ying的枚举值
    public static OperateEnum valueOf(String s)
    {
        return (OperateEnum)Enum.valueOf(OperateEnum, s);
    }
    
    //私You的构造函数
    private OperateEnum(String s, int i, String s1, int j)
    {
        super(s, i);
        name = s1;
        index = j;
    }

    public String getName()
    {
        return name;
    }

    public void setName(String s)
    {
        name = s;
    }

    public int getIndex()
    {
        return index;
    }

    public void setIndex(int i)
    {
        index = i;
    }

    //static final类型
    public static final OperateEnum ADD;
    public static final OperateEnum SUBTRACT;
    public static final OperateEnum MULTIPLY;
    public static final OperateEnum DIVIDE;
    
    private String name;
    private int index;
    
    private static final OperateEnum $VALUES[];

    //静态代码块,在类执行clinit的时候,执行
    static 
    {
        ADD = new OperateEnum("ADD", 0, "add", 1);
        SUBTRACT = new OperateEnum("SUBTRACT", 1, "subtract", 2);
        MULTIPLY = new OperateEnum("MULTIPLY", 2, "multiply", 3);
        DIVIDE = new OperateEnum("DIVIDE", 3, "divide", 4);
        $VALUES = (new OperateEnum[] {
            ADD, SUBTRACT, MULTIPLY, DIVIDE
        });
    }
}

枚举类和普通类的区别:

  • 如果有构造器,必须用private修饰
  • 枚举类不能派生子类
  • 枚举类所有的实例必须在第一行显示定义。系统会自动给这些实例加上public static final修饰,无须程序员显示定义
  • 枚举类默认提供了values()方法方便遍历所有的枚举值

2、抽象类Enum

Enum类结构
在这里插入图片描述
enum中的方法(Enum提供的方法)

  • public final int compareTo(E o) 比较相同类型的枚举值ordinal
  • public final int ordinal() 返回枚举的索引值,第一个枚举值从零开始
  • public final String name() 返回枚举实例名称
  • public String toString() 返回枚举常量名称
  • valueOf(String)
  • getDeclaringClass() 返回与此枚举常量对应的Class对象枚举类型
  • equals(Object other) other==this的时候,才返回true
  • clone() 和 readObject()(YongYu反序列化):这2个方法均抛出Yi常,从而保证不能生成新的实例,保证了真正的单例

open jdk 1.8

package java.lang;

import java.io.Serializable;
import java.io.IOException;
import java.io.InvalidObjectException;
import java.io.ObjectInputStream;
import java.io.ObjectStreamException;

//这是所有Java语言枚举类型的公共基类
public abstract class Enum<E extends Enum<E>>
        implements Comparable<E>, Serializable {

	/**
      *此枚举常量的名称,如枚举声明中声明的那样。
      *大多数程序员应该使用{@link #toString}方法而不是
      *访问此字段。
     */
    private final String name;

    /**
      *返回此枚举常量的名称,与其中声明的完全相同
      *枚举声明。
     *
      * <b>大多数程序员应该使用{@link #toString}方法
      *优先于此,因为toString方法可能会返回
      *更友好的用户名。</ b>此方法主要用于
      *在特殊情况下使用,正确性取决于获得
      *确切名称,不会因版本而异。
     *
      * @return此枚举常量的名称
     */
    public final String name() {
        return name;
    }

	 /**
      *此枚举常数的序数(其位置
      *在枚举声明中,分配初始常量
      *序数为零)。
     *
      *大多数程序员对此字段没有用处。 它是专门设计的
      *供复杂的基于枚举的数据结构使用,例如
      * {@link java.util.EnumSet}和{@link java.util.EnumMap}。
     */
    private final int ordinal;

	 /**
      *返回此枚举常量的序数(其位置
      *在其枚举声明中,其中分配了初始常量
      *序数为零)。
     *
      *大多数程序员都没有使用此方法。 它是
      *设计用于复杂的基于枚举的数据结构,例如
      *作为{@link java.util.EnumSet}和{@link java.util.EnumMap}。
     *
      * @return此枚举常量的序数
     */
    public final int ordinal() {
        return ordinal;
    }

    /**
      *唯一的构造函数。 程序员无法调用此构造函数。
      *它由编译器响应的代码使用
      *枚举类型声明。
     *
      * @param name  - 此枚举常量的名称,即标识符
      *用于申报。
      * @param ordinal  - 此枚举常量的序数(其位置
      *在枚举声明中,分配初始常量
      *序数为零)。
     */
    protected Enum(String name, int ordinal) {
        this.name = name;
        this.ordinal = ordinal;
    }

	/**
      * @return此枚举常量的名称
     */
    public String toString() {
        return name;
    }

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

    /**
     * Returns a hash code for this enum constant.
     *
     * @return a hash code for this enum constant.
     */
    public final int hashCode() {
        return super.hashCode();
    }

	/**
      *抛出CloneNotSupportedException。 这保证了枚举
      *永远不会被克隆,这是保持“单例”所必需的
      * 状态。
     *
      * @return(永不返回)
     */
    protected final Object clone() throws CloneNotSupportedException {
        throw new CloneNotSupportedException();
    }

    /**
     * Compares this enum with the specified object for order.  Returns a
     * negative integer, zero, or a positive integer as this object is less
     * than, equal to, or greater than the specified object.
     *
     * Enum constants are only comparable to other enum constants of the
     * same enum type.  The natural order implemented by this
     * method is the order in which the constants are declared.
     */
    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;
    }

    /**
     * @return与此枚举常量对应的Class对象枚举类型
     */
    @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() { }

    /**
     * 防止默认的反序列化,so,反序列化的时候,不能生成新的实例,保证了真正的单例
     */
    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");
    }
}

3、总结

枚举本质上是通过普通的类来实现的,只是编译器为我们进行了处理。每个枚举类型都继承自 java.lang.Enum,并自动添加了 values 和 valueOf 方法。而每个枚举常量是一个静态常量字段,使用内部类实现,该内部类继承了枚举类。所有枚举常量都通过静态代码块来进行初始化,即在类加载期间就初始化。另外通过把 clone、readObject、writeObject 这三个方法定义为 final 的,同时实现是抛出相应的异常。这样保证了每个枚举类型及枚举常量都是不可变的。可以利用枚举的这两个特性来实现线程安全的单例


参考
https://blog.csdn.net/niuzhucedenglu/article/details/79540799

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值