源码阅读-java基础-java.lang.Enum

1、引言

枚举类型是 JDK 5 之后引进的一种非常重要的引用类型,可以用来定义一系列枚举常量。相比与常量(public static final定义),在安全性、指意性、可读性方面更胜一筹。另外它可以和switch case搭配使用。

2、类定义

实际上在使用关键字enum创建枚举类型并编译后,编译器会为我们生成一个相关的类,这个类继承了Java API中的java.lang.Enum类,也就是说通过关键字enum创建枚举类型在编译后事实上也是一个类类型而且该类继承自java.lang.Enum类,并且该类类型是final修饰的,无法被继承。

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

3、成员属性

// 枚举常量的名称
private final String name;

// 它和不重写的toString()方法返回的是一样的,只不过toString()方法可以进行重写定制。
public final String name() {
    return name;
}

/**
 * 枚举常量的序号(它在枚举声明中的位置,其中初始常量的序号为零)。
 * 代码中尽量避免使用该值,因为我们有时候添加新枚举时,总是“按组”放在一起,不会放到最后,除非强制要求。
 * 比如接口响应码的枚举,我们通常会把参数异常的放一组,内部异常的放一组等。如果参数异常新添加一个枚举“xx不存在”,如果这个枚举没有放在整个接口响应码枚举的末尾,而是放到了某一组的末尾,那么部分枚举常量的ordinal值就发生了变化。这将是灾难性的,所以要么代码规范添加新枚举只能添加到末尾;要么不使用该值。
 */
private final int ordinal;

public final int ordinal() {
    return ordinal;
}

4、构造方法

// 唯一的构造方法,程序员调用不到,它由编译器发出的代码用于响应枚举类型声明。
protected Enum(String name, int ordinal) {
    this.name = name;
    this.ordinal = ordinal;
}

5、其他方法

// 返回声明中包含的此枚举常量的名称。 可以覆盖该方法,但通常不需要或不需要。
public String toString() {
    return name;
}

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

// 这里调用的是Object的hashCode方法
public final int hashCode() {
    return super.hashCode();
}

// 不能克隆,保证了枚举永远是单例的,所以枚举是单例模式的典型代表
protected final Object clone() throws CloneNotSupportedException {
    throw new CloneNotSupportedException();
}

// 这里需要注意,底层的实现用的是ordinal实现的,即比较的是枚举常量的序号。
public final int compareTo(E o) {
    Enum<?> other = (Enum<?>)o;
    Enum<E> self = this;
    if (self.getClass() != other.getClass() && 
        self.getDeclaringClass() != other.getDeclaringClass())
        throw new ClassCastException();
    return self.ordinal - other.ordinal;
}

// 返回与此枚举常量的枚举类型相对应的 Class 对象。
public final Class<E> getDeclaringClass() {
    Class<?> clazz = getClass();
    Class<?> zuper = clazz.getSuperclass();
    return (zuper == Enum.class) ? (Class<E>)clazz : (Class<E>)zuper;
}

// 枚举不能有finalize方法
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");
}    
/**
 * 返回简单名称到枚举常量的映射。
 * name的值必须与用于声明此类型的枚举常量的标识符完全一致。
 *
 * 对于特定的枚举类型T,有两个隐式声明的方法可以直接使用:
 *  1) public static T valueOf(String)  根据名称获取单个枚举类型;这个我深有体会,因为之前是不知道有这个方法,通常是用values()获取枚举集合map,然后遍历
 *  2) public static T[] values()   获取所有枚举类型数组;
 */
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);
}

/**
 * 1)该方法是属于java.lang.Class,不是java.lang.Enum的方法;
 * 2)enumConstantDirectory 是一个map,定义如下:private volatile transient Map<String, T> enumConstantDirectory = null;其中key为枚举的name,value为枚举。
 * 3)enumConstantDirectory()方法获取枚举常量目录,没有就继续调用getEnumConstantsShared();如果有返回值,就遍历put进enumConstantDirectory。
 */
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;
}

7、枚举隐式实现的方法

如上所说,枚举自动继承这两个隐式方法。这两个方法很重要,所以我在这里单拎出来了。

// 根据名称获取单个枚举类型
public static T valueOf(String){}

// 获取所有枚举类型数组
public static T[] values(){}   

8、枚举集合

这两个是枚举优化过后的集合,比HashSet,HashMap的性能更高。

8.1、EnumSet

源码阅读-java基础-java.util.EnumSet

8.2、EnumMap

源码阅读-java基础-java.util.EnumMap



posted @ 2020-12-08 10:46  Erneste  阅读(166)  评论(0)    收藏  举报