1. 程式人生 > >java列舉類初探-語法糖-反編譯

java列舉類初探-語法糖-反編譯

最近接觸了“語法糖”這個概念,今天又看了一下列舉類的知識點,主要還是看它的用法,之前一直沒有怎麼用過java列舉類,看了李剛那本《瘋狂java講義》的列舉類章節,算是把它的用法弄明白了。

可是列舉類是一種“語法糖”,也就是說只有編譯器知道“enum”關鍵字,jvm是不知道的,位元組碼檔案中沒有列舉這一概念。實際上,書中一開頭就提到了在枚舉出現前,程式設計師需要自己程式設計實現列舉(具體就不展開了),比較複雜,JDK1.5之後出現了enum列舉類(可以看做是一種特殊的java類)——作為一種“語法糖”讓程式設計師更方便地實現列舉,對程式設計師更加友好、“甜蜜”了,哈哈。

我對java語法糖的理解是這樣的:可以看做編譯器先把原來的enum類編譯成“正常的java類”,然後再以正常的方式編譯成位元組碼,所以位元組碼當然不知道有“語法糖”的存在啦,不知道我的理解有沒有錯,應該是沒有什麼大問題,如果有的話還請各位大神指正。
為了更好的理解列舉類是怎麼實現的,我先是按照書中對列舉類的定義寫了一個對應於enum類的“正常的java類”,程式碼如下:

import java.lang.Enum;
/*
public enum TrueEnum {
    WHITE, BLACK;
}
*/
public class MyEnum extends Enum { // 這樣寫肯定是通不過編譯的,因為編譯器不允許我們的類顯示的繼承Enum類

    private MyEnum() {}

    public static final MyEnum e1 = new MyEnum("WHITE", 0);
    public static final MyEnum e2 = new MyEnum("BLACK", 1);

    public
MyEnum[] values() { return new MyEnum[]{e1, e2}; // 這個地方有問題,等下指出 } }

後來想反編譯一下TrueEum.class(這個是enum類),和自己寫的程式碼對比一下看對不對,就下了一個反編譯程式jd-gui,沒想到這個程式太高階了,直接反編譯成enum類了(囧),又不知道怎麼弄成“低階”的,就直接上網搜了別人的部落格,看他們貼出的反編譯程式碼,發現自己的猜想還是基本正確的,除了values()方法,正確的實現應該是返回陣列的一個淺拷貝(return array.clone()),而不是像我這樣簡單的返回一個數組引用,後來想想:如果呼叫者搞破壞怎麼辦?比如通過資料引用把某個資料元素換成其他值不就破壞了原物件的封裝性了嗎。看來自己還是too young。

看了兩三篇部落格,這篇寫的不錯:Java 列舉原始碼分析主要是排版看起來比較舒服,分析的也比較全面。

不過還有一點值得注意的是,這篇文章沒有指出enum類實現介面和新增抽象方法這兩種情況,這樣的話,列舉值就不是作為列舉類的例項了,而是作為列舉類的匿名子類的實現類。
也就是說列舉值要麼是Enum的直接子類要麼是Enum的“孫子類”(這個詞是我發明的,理解意思就好,蛤蛤),知道這點的話,下面這段Enum的原始碼就很好理解了:

// 得到列舉常量所屬列舉型別的Class物件  
public final Class<E> getDeclaringClass() {  
    Class clazz = getClass();  
    Class zuper = clazz.getSuperclass();  
    return (zuper == Enum.class) ? clazz : zuper;  
}

這是我基於剛才提到的那篇部落格做的一點補充,做了一點微薄的貢獻,謝謝大家。
第一次發表部落格,就先這樣吧,獻醜了,歡迎各位朋友批評指正。