Enum+多態(tài),我沒說錯,不過Enum是不可以被繼承的,也不可以繼承自別人,只是能實現(xiàn)接口而已,何談多態(tài)?
不過還是先看看“現(xiàn)象”吧:
以上是一個簡單的enum,關(guān)于它,我要補充一點:
Fruit是java.lang.Enum的 子類 ,準確地說,是Enum<Fruit>的子類,這里出現(xiàn)了一個繼承關(guān)系,不過這個繼承是編譯器幫我們做的,我們不能顯式地去做。不信的話我們可以試著用一個Enum<Fruit>的引用去指向一個APPLE,肯定是沒問題的,我就不再試了。
為了更直觀地說明這一點,我們來看看Fruit的反編譯結(jié)果吧:
注意這幾行:
看來JDK Enum的實現(xiàn)也不過就是沿襲了Effective Java中提出的TypeSafeEnum模式,只不過是在編譯器和JVM等更底層的級別上提供了支持。
至此,至少說明了Fruit和Enum的繼承關(guān)系,但問題是: 現(xiàn)在不能繼續(xù)再從Fruit派生子類,那么哪來的多態(tài)呢?
還是再多寫點代碼吧:
其中,只有Orange沒有Overide test()方法;
我們在主函數(shù)中調(diào)用它們:
輸出結(jié)果:
可以看到,重新定義了test方法的APPLE,PEAR,PEACH覆蓋了從父類繼承過來的默認行為,而未從新定義test方法的ORANGE卻沿襲了父類的行為,多態(tài)性在這里展現(xiàn)出來了。
那么我們剛才明明看見過Fruit的反編譯結(jié)果,沒有任何新類繼承自Fruit,那么這些多態(tài)行為是哪里冒出來的呢?說它是“多態(tài)”是否準確呢?
其實,F(xiàn)ruit類在這個時候已經(jīng)發(fā)生了微妙的變化,一切都與JDK的Enum的實現(xiàn)有關(guān),我們現(xiàn)在可以到編譯結(jié)果目錄下面看看:
怎么除了Fruit.class之外,還多了幾個貌似是內(nèi)部類的class文件??也許看到這里我們能有點線索了,不過還是在這個時候在看看反編譯結(jié)果吧,看看它到底在搞什么鬼:
注意這段代碼:
這個時候的APPLE,PEAR,PEACH已經(jīng)以匿名內(nèi)部類的方式對Fruit進行了Overide,自然體現(xiàn)出了多態(tài),多出的那三個疑似內(nèi)部類的class文件也就是它們!而ORANGE,沒有重寫test方法,仍然以一個Fruit實例的形式出現(xiàn)。
關(guān)于Enum為什么會有多態(tài)大概也就這么點貓膩了,那我們來考慮一下它有多大價值吧?
我們或許可以利用這一點來改造Strategy模式,傳統(tǒng)的Strategy會產(chǎn)生出稍微多一些的父類、子類,而如果用Enum的話,“一個類”(對程序作者來講)就能搞定,能簡化一下類層次,再說了,用枚舉來表示區(qū)分各種不同策略也是很合情理的,所以,Java Enum的這點小小特性感覺還是比較有前途發(fā)揮一些作用的,起碼在代碼組織上;
更多應用可能或是局限性就還需要逐步在實際應用中摸索。
不過還是先看看“現(xiàn)象”吧:
public enum Fruit { APPLE, PEAR, PEACH, ORANGE; }
以上是一個簡單的enum,關(guān)于它,我要補充一點:
Fruit是java.lang.Enum的 子類 ,準確地說,是Enum<Fruit>的子類,這里出現(xiàn)了一個繼承關(guān)系,不過這個繼承是編譯器幫我們做的,我們不能顯式地去做。不信的話我們可以試著用一個Enum<Fruit>的引用去指向一個APPLE,肯定是沒問題的,我就不再試了。
為了更直觀地說明這一點,我們來看看Fruit的反編譯結(jié)果吧:
package test; public final class Fruit extends Enum { private Fruit(String s, int i) { super(s, i); } public static Fruit[] values() { Fruit afruit[]; int i; Fruit afruit1[]; System.arraycopy(afruit = ENUM$VALUES, 0, afruit1 = new Fruit[i = afruit.length], 0, i); return afruit1; } public static Fruit valueOf(String s) { return (Fruit)Enum.valueOf(test/Fruit, s); } public static final Fruit APPLE; public static final Fruit PEAR; public static final Fruit PEACH; public static final Fruit ORANGE; private static final Fruit ENUM$VALUES[]; static { APPLE = new Fruit("APPLE", 0); PEAR = new Fruit("PEAR", 1); PEACH = new Fruit("PEACH", 2); ORANGE = new Fruit("ORANGE", 3); ENUM$VALUES = (new Fruit[] { APPLE, PEAR, PEACH, ORANGE }); } }
注意這幾行:
public static final Fruit APPLE; public static final Fruit PEAR; public static final Fruit PEACH; public static final Fruit ORANGE;
看來JDK Enum的實現(xiàn)也不過就是沿襲了Effective Java中提出的TypeSafeEnum模式,只不過是在編譯器和JVM等更底層的級別上提供了支持。
至此,至少說明了Fruit和Enum的繼承關(guān)系,但問題是: 現(xiàn)在不能繼續(xù)再從Fruit派生子類,那么哪來的多態(tài)呢?
還是再多寫點代碼吧:
public enum Fruit { APPLE { public void test() { System.out.println("I am an apple."); } }, PEAR { public void test() { System.out.println("I am a pear."); } }, PEACH { public void test() { System.out.println("I am a peach."); } }, ORANGE; public void test() { System.out.println("I am a fruit."); } }
其中,只有Orange沒有Overide test()方法;
我們在主函數(shù)中調(diào)用它們:
public static void main(String[] args) { Fruit.APPLE.test(); Fruit.PEAR.test(); Fruit.PEACH.test(); Fruit.ORANGE.test(); }
輸出結(jié)果:
引用
I am an apple.
I am a pear.
I am a peach.
I am a fruit.
I am a pear.
I am a peach.
I am a fruit.
可以看到,重新定義了test方法的APPLE,PEAR,PEACH覆蓋了從父類繼承過來的默認行為,而未從新定義test方法的ORANGE卻沿襲了父類的行為,多態(tài)性在這里展現(xiàn)出來了。
那么我們剛才明明看見過Fruit的反編譯結(jié)果,沒有任何新類繼承自Fruit,那么這些多態(tài)行為是哪里冒出來的呢?說它是“多態(tài)”是否準確呢?
其實,F(xiàn)ruit類在這個時候已經(jīng)發(fā)生了微妙的變化,一切都與JDK的Enum的實現(xiàn)有關(guān),我們現(xiàn)在可以到編譯結(jié)果目錄下面看看:

怎么除了Fruit.class之外,還多了幾個貌似是內(nèi)部類的class文件??也許看到這里我們能有點線索了,不過還是在這個時候在看看反編譯結(jié)果吧,看看它到底在搞什么鬼:
// Decompiled by Jad v1.5.8e. Copyright 2001 Pavel Kouznetsov. // Jad home page: http://www.geocities.com/kpdus/jad.html // Decompiler options: packimports(3) // Source File Name: Fruit.java package test; import java.io.PrintStream; public class Fruit extends Enum { private Fruit(String s, int i) { super(s, i); } public void test() { System.out.println("I am a fruit."); } public static Fruit[] values() { Fruit afruit[]; int i; Fruit afruit1[]; System.arraycopy(afruit = ENUM$VALUES, 0, afruit1 = new Fruit[i = afruit.length], 0, i); return afruit1; } public static Fruit valueOf(String s) { return (Fruit)Enum.valueOf(test/Fruit, s); } Fruit(String s, int i, Fruit fruit) { this(s, i); } public static final Fruit APPLE; public static final Fruit PEAR; public static final Fruit PEACH; public static final Fruit ORANGE; private static final Fruit ENUM$VALUES[]; static { APPLE = new Fruit("APPLE", 0) { public void test() { System.out.println("I am an apple."); } }; PEAR = new Fruit("PEAR", 1) { public void test() { System.out.println("I am a pear."); } }; PEACH = new Fruit("PEACH", 2) { public void test() { System.out.println("I am a peach."); } }; ORANGE = new Fruit("ORANGE", 3); ENUM$VALUES = (new Fruit[] { APPLE, PEAR, PEACH, ORANGE }); } }
注意這段代碼:
static { APPLE = new Fruit("APPLE", 0) { public void test() { System.out.println("I am an apple."); } }; PEAR = new Fruit("PEAR", 1) { public void test() { System.out.println("I am a pear."); } }; PEACH = new Fruit("PEACH", 2) { public void test() { System.out.println("I am a peach."); } }; ORANGE = new Fruit("ORANGE", 3);
這個時候的APPLE,PEAR,PEACH已經(jīng)以匿名內(nèi)部類的方式對Fruit進行了Overide,自然體現(xiàn)出了多態(tài),多出的那三個疑似內(nèi)部類的class文件也就是它們!而ORANGE,沒有重寫test方法,仍然以一個Fruit實例的形式出現(xiàn)。
關(guān)于Enum為什么會有多態(tài)大概也就這么點貓膩了,那我們來考慮一下它有多大價值吧?
我們或許可以利用這一點來改造Strategy模式,傳統(tǒng)的Strategy會產(chǎn)生出稍微多一些的父類、子類,而如果用Enum的話,“一個類”(對程序作者來講)就能搞定,能簡化一下類層次,再說了,用枚舉來表示區(qū)分各種不同策略也是很合情理的,所以,Java Enum的這點小小特性感覺還是比較有前途發(fā)揮一些作用的,起碼在代碼組織上;
更多應用可能或是局限性就還需要逐步在實際應用中摸索。
更多文章、技術(shù)交流、商務(wù)合作、聯(lián)系博主
微信掃碼或搜索:z360901061

微信掃一掃加我為好友
QQ號聯(lián)系: 360901061
您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點擊下面給點支持吧,站長非常感激您!手機微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對您有幫助就好】元
