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

怎么除了Fruit.class之外,還多了幾個貌似是內部類的class文件??也許看到這里我們能有點線索了,不過還是在這個時候在看看反編譯結果吧,看看它到底在搞什么鬼:
// 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已經以匿名內部類的方式對Fruit進行了Overide,自然體現出了多態,多出的那三個疑似內部類的class文件也就是它們!而ORANGE,沒有重寫test方法,仍然以一個Fruit實例的形式出現。
關于Enum為什么會有多態大概也就這么點貓膩了,那我們來考慮一下它有多大價值吧?
我們或許可以利用這一點來改造Strategy模式,傳統的Strategy會產生出稍微多一些的父類、子類,而如果用Enum的話,“一個類”(對程序作者來講)就能搞定,能簡化一下類層次,再說了,用枚舉來表示區分各種不同策略也是很合情理的,所以,Java Enum的這點小小特性感覺還是比較有前途發揮一些作用的,起碼在代碼組織上;
更多應用可能或是局限性就還需要逐步在實際應用中摸索。
更多文章、技術交流、商務合作、聯系博主
微信掃碼或搜索:z360901061

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