Enum+多態,我沒說錯,不過Enum是不能夠被繼承的,也不能夠繼承自別人,只是能實現接口而已,何談多態?
不過仍是先看看「現象」吧:
html
public enum Fruit { APPLE, PEAR, PEACH, ORANGE; }
以上是一個簡單的enum,關於它,我要補充一點:
Fruit是java.lang.Enum的子類,準確地說,是Enum<Fruit>的子類,這裏出現了一個繼承關係,不過這個繼承是編譯器幫咱們作的,咱們不能顯式地去作。不信的話咱們能夠試着用一個Enum<Fruit>的引用去指向一個APPLE,確定是沒問題的,我就再也不試了。
爲了更直觀地說明這一點,咱們來看看Fruit的反編譯結果吧:
app
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派生子類,那麼哪來的多態呢?
仍是再多寫點代碼吧:
this
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()方法;
咱們在主函數中調用它們:
code
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.
能夠看到,從新定義了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的這點小小特性感受仍是比較有前途發揮一些做用的,起碼在代碼組織上;
更多應用可能或是侷限性就還須要逐步在實際應用中摸索。