Java學習(23) -- 源碼閱讀(Enum)

package java.lang;

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

/*
聲明方法的描述,請參見The Java™ Language Specification的第8.9 節 。 
請注意,當使用枚舉類型作爲集合的類型或映射中的鍵的類型時,可以使用專門且高效的set和map實現。 

從以下版本開始: 
1.5 
另請參見: 
Class.getEnumConstants() , EnumSet , EnumMap , Serialized Form 
 */
public abstract class Enum<E extends Enum<E>>
        implements Comparable<E>, Serializable {
/*
枚舉常量的名稱,如枚舉聲明中聲明的那樣。 
大多數程序員應該使用toString方法而不是訪問此字段。
返回:
      枚舉常量的名稱
 */            
    private final String name;

/*
返回此枚舉常量的名稱,與其枚舉聲明中聲明的完全相同。 
大多數程序員應優先使用toString方法,因爲toString方法可能返回一個更加用戶友好的名稱。 
方法主要用於特殊情況,
其中正確性取決於獲取確切名稱,該名稱在不同版本之間不會有所不同。 這個枚舉常量的名稱
 */
    public final String name() {
        return name;
    }

/*
此枚舉常量的序數(它在枚舉聲明中的位置,其中初始常量的序數爲零)。 
大多數程序員都不會使用這個領域。 它設計用於複雜的基於枚舉的數據結構,、
例如java.util.EnumSet和java.util.EnumMap。
 */    
    private final int ordinal;

/*
返回此枚舉常量的序數(它在枚舉聲明中的位置,其中初始常量的序數爲零)。 
大多數程序員都沒有使用這種方法。 
它設計用於複雜的基於枚舉的數據結構,例如java.util.EnumSet和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;
    }

    /**
     * 如果指定的對象等於此枚舉常量,則返回true。
     *
     * @param other 要與此對象進行相等性比較的對象。
     * @return  如果指定的對象等於此枚舉常量,則返回true。
     */
    public final boolean equals(Object other) {
        return this==other;
    }

    /**
     * 返回此枚舉常量的哈希碼。
     *
     * @return 此枚舉常量的哈希碼。
     */
    public final int hashCode() {
        return super.hashCode();
    }

    /**
     * 拋出CloneNotSupportedException。 
     * 這保證了枚舉永遠不會被克隆,這是保持其“單身”狀態所必需的。
     *
     * @return (never returns)
     */
    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;
    }

    /**
     * 返回與此枚舉常量的枚舉類型相對應的Class對象。 
     * 當且僅當e1.getDeclaringClass()== e2.getDeclaringClass())時,
     * 兩個枚舉常量e1和e2具有相同的枚舉類型。 
     * (此方法返回的值可能與使用常量特定類體的枚舉常數Object.getClass()方法返回的值不同) 
     *
     * @return 該類對象對應於此枚舉常量的枚舉類型 
     */
    @SuppressWarnings("unchecked")
    public final Class<E> getDeclaringClass() {
        Class<?> clazz = getClass();
        Class<?> zuper = clazz.getSuperclass();
        return (zuper == Enum.class) ? (Class<E>)clazz : (Class<E>)zuper;
    }

    /**
     * 返回具有指定名稱的指定枚舉類型的枚舉常量。 
     * 該名稱必須與用於聲明此類型的枚舉常量的標識符完全一致。 
     * (不允許使用外來空白字符。) 
     *
     * 請注意,對於特定枚舉類型T ,
     * 可以使用該枚舉上隱式聲明的public static T valueOf(String)方法,
     * 而不是使用此方法將名稱映射到相應的枚舉常量。 
     * 枚舉類型的所有常量可以通過調用該類型的隱式public static T[] values()方法來獲得。 
     * @param <T> T - 要返回其常量的枚舉類型 
     * @param enumType  類返回常量的枚舉類型的 類對象 

     * @param name 常量返回的名稱 
     * @return 具有指定名稱的指定枚舉類型的枚舉常量
     * @throws IllegalArgumentException 如果指定的枚舉類型沒有指定名稱的常量,或者指定的類對象不表示枚舉類型 

     * @throws NullPointerException 如果 enumType或 name爲null 

     * @since 1.5
     */
    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);
    }
    /*
    可以看到,enumType.enumConstantDirectory().get(name);enumType這個枚舉類抵用enumConstantDirectory方法
    拿到這個枚舉類的map,代碼如下。然後根據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;
    }
    enumConstantDirectory()方法獲取枚舉常量目錄,沒有就繼續調用getEnumConstantsShared();如果有返回值,就遍歷put進enumConstantDirectory。然後返回。方法說明如下
    getEnumConstantsShared();返回此枚舉類的元素,如果此Class對象不表示枚舉類型,則返回null; 
    與getEnumConstants相同,但結果是由所有調用者取消克隆,緩存和共享。

     */

    /**
     * 枚舉類不能有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");
    }
}

枚舉是如何保證線程安全的

當一個Java類第一次被真正使用到的時候靜態資源被初始化、Java類的加載和初始化過程都是線程安全的。所以,創建一個enum類型是線程安全的。

爲什麼用枚舉實現的單例是最好的方式

1. 枚舉寫法簡單

2. 枚舉自己處理序列化

3.枚舉實例創建是thread-safe(線程安全的)

參考文獻
http://blog.jobbole.com/94074/

http://blog.jrwang.me/2016/java-enum/
--------------------- 
作者:suveng 
來源:CSDN 
原文:https://blog.csdn.net/qq_37933685/article/details/80951000 
版權聲明:本文爲博主原創文章,轉載請附上博文鏈接!

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章