java源碼學習(三)Enum


Enum

Enum類是java.lang包中一個類,他是Java語言中所有枚舉類型的公共基類。

一、定義

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

1.抽象類

首先,抽象類不能被實例化,所以我們在java程序中不能使用new關鍵字來聲明一個Enum,如果想要定義可以使用這樣的語法:

enum enumName{
    value1,value2
    method1(){}
    method2(){}
}

其次,看到抽象類,第一印象是肯定有類繼承他。至少我們應該是可以繼承他的,所以:

public class testEnum extends Enum{
}
public class testEnum extends Enum<Enum<E>>{
}
public class testEnum<E> extends Enum<Enum<E>>{
}

嘗試了以上三種方式之后,得出以下結論:Enum類無法被繼承。

為什么一個抽象類不讓繼承?enum定義的枚舉是怎么來的?難道不是對Enum的一種繼承嗎?帶着這些疑問我們來反編譯以下代碼:

enum Color {RED, BLUE, GREEN}

編譯器將會把他轉成如下內容:

public final class Color extends Enum<Color> {
  public static final Color[] values() { return (Color[])$VALUES.clone(); }
  public static Color valueOf(String name) { ... }

  private Color(String s, int i) { super(s, i); }

  public static final Color RED;
  public static final Color BLUE;
  public static final Color GREEN;

  private static final Color $VALUES[];

  static {
    RED = new Color("RED", 0);
    BLUE = new Color("BLUE", 1);
    GREEN = new Color("GREEN", 2);
    $VALUES = (new Color[] { RED, BLUE, GREEN });
  }
}

短短的一行代碼,被編譯器處理過之后竟然變得這么多,看來,enmu關鍵字是java提供給我們的一個語法糖啊。。。從反編譯之后的代碼中,我們發現,編譯器不讓我們繼承Enum,但是當我們使用enum關鍵字定義一個枚舉的時候,他會幫我們在編譯后默認繼承java.lang.Enum類,而不像其他的類一樣默認繼承Object類。且采用enum聲明后,該類會被編譯器加上final聲明,故該類是無法繼承的。 PS:由於JVM類初始化是線程安全的,所以可以采用枚舉類實現一個線程安全的單例模式。

2.實現ComparableSerializable接口

Enum實現了Serializable接口,可以序列化。 Enum實現了Comparable接口,可以進行比較,默認情況下,只有同類型的enum才進行比較(原因見后文),要實現不同類型的enum之間的比較,只能復寫compareTo方法。

3.泛型:<E extends Enum<E>>

怎么理解<E extends Enum<E>>?

首先,這樣寫只是為了讓Java的API更有彈性,他主要是限定形態參數實例化的對象,故要求只能是Enum,這樣才能對 compareTo 之類的方法所傳入的參數進行形態檢查。所以,我們完全可以不必去關心他為什么這么設計。

這里倒是可以關注一下泛型中extends的用法,以及K V O T E ? object這幾個符號之間的區別。

好啦,我們回到這個令人實在是無法理解的<E extends Enum >

首先我們先來“翻譯”一下這個Enum<E extends Enum >到底什么意思,然后再來解釋為什么Java要這么用。 我們先看一個比較常見的泛型:List 。這個泛型的意思是,List中存的都是String類型,告訴編譯器要接受String類型,並且從List中取出內容的時候也自動幫我們轉成String類型。 所以Enum<E extends Enum >可以暫時理解為Enum里面的內容都是E extends Enum 類型。 這里的E我們就理解為枚舉,extends表示上界,比如: List<? extends Object>,List中的內容可以是Object或者擴展自Object的類。這就是extends的含義。 所以,E extends Enum 表示為一個繼承了Enum 類型的枚舉類型。 那么,Enum<E extends Enum >就不難理解了,就是一個Enum只接受一個Enum或者他的子類作為參數。相當於把一個子類或者自己當成參數,傳入到自身,引起一些特別的語法效果。

二、屬性

在Enum中,有兩個成員變量,一個是名字(name),一個是序號(ordinal)。 序號是一個枚舉常量,表示在枚舉中的位置,從0開始,依次遞增。

private final String name;
public final String name() {
    return name;
}
private final int ordinal;
public final int ordinal() {
    return ordinal;
}

三、方法

1. 構造方法

前面我們說過,Enum是一個抽象類,不能被實例化,但是他也有構造函數,從前面我們反編譯出來的代碼中,我們也發現了Enum的構造函數,在Enum中只有一個保護類型的構造函數:

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

文章開頭反編譯的代碼中private Color(String s, int i) { super(s, i); }中的super(s, i);就是調用Enum中的這個保護類型的構造函數來初始化name和ordinal。

2. 其它方法

	public String toString() {
		return name;
	}

    public final boolean equals(Object other) {
        return this==other;
    }
    
    public final int hashCode() {
        return super.hashCode();
    }
    
    public final int compareTo(E o) {
        Enum other = (Enum)o;
        Enum self = this;
        if (self.getClass() != other.getClass() && // optimization
            self.getDeclaringClass() != other.getDeclaringClass())
            throw new ClassCastException();
        return self.ordinal - other.ordinal;
    }
    
    public final Class<E> getDeclaringClass() {
        Class clazz = getClass();
        Class zuper = clazz.getSuperclass();
        return (zuper == Enum.class) ? clazz : 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);
    }

四、參考資料

http://www.hollischuang.com/archives/92


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM