Enum+多態(tài),我沒說錯(cuò),不過Enum是不可以被繼承的,也不可以繼承自別人,只是能實(shí)現(xiàn)接口而已,何談多態(tài)?
不過還是先看看“現(xiàn)象”吧:
以上是一個(gè)簡(jiǎn)單的enum,關(guān)于它,我要補(bǔ)充一點(diǎn):
Fruit是java.lang.Enum的 子類 ,準(zhǔn)確地說,是Enum<Fruit>的子類,這里出現(xiàn)了一個(gè)繼承關(guān)系,不過這個(gè)繼承是編譯器幫我們做的,我們不能顯式地去做。不信的話我們可以試著用一個(gè)Enum<Fruit>的引用去指向一個(gè)APPLE,肯定是沒問題的,我就不再試了。
為了更直觀地說明這一點(diǎn),我們來看看Fruit的反編譯結(jié)果吧:
注意這幾行:
看來JDK Enum的實(shí)現(xiàn)也不過就是沿襲了Effective Java中提出的TypeSafeEnum模式,只不過是在編譯器和JVM等更底層的級(jí)別上提供了支持。
至此,至少說明了Fruit和Enum的繼承關(guān)系,但問題是: 現(xiàn)在不能繼續(xù)再從Fruit派生子類,那么哪來的多態(tài)呢?
還是再多寫點(diǎn)代碼吧:
其中,只有Orange沒有Overide test()方法;
我們?cè)谥骱瘮?shù)中調(diào)用它們:
輸出結(jié)果:
可以看到,重新定義了test方法的APPLE,PEAR,PEACH覆蓋了從父類繼承過來的默認(rèn)行為,而未從新定義test方法的ORANGE卻沿襲了父類的行為,多態(tài)性在這里展現(xiàn)出來了。
那么我們剛才明明看見過Fruit的反編譯結(jié)果,沒有任何新類繼承自Fruit,那么這些多態(tài)行為是哪里冒出來的呢?說它是“多態(tài)”是否準(zhǔn)確呢?
其實(shí),F(xiàn)ruit類在這個(gè)時(shí)候已經(jīng)發(fā)生了微妙的變化,一切都與JDK的Enum的實(shí)現(xiàn)有關(guān),我們現(xiàn)在可以到編譯結(jié)果目錄下面看看:
怎么除了Fruit.class之外,還多了幾個(gè)貌似是內(nèi)部類的class文件??也許看到這里我們能有點(diǎn)線索了,不過還是在這個(gè)時(shí)候在看看反編譯結(jié)果吧,看看它到底在搞什么鬼:
注意這段代碼:
這個(gè)時(shí)候的APPLE,PEAR,PEACH已經(jīng)以匿名內(nèi)部類的方式對(duì)Fruit進(jìn)行了Overide,自然體現(xiàn)出了多態(tài),多出的那三個(gè)疑似內(nèi)部類的class文件也就是它們!而ORANGE,沒有重寫test方法,仍然以一個(gè)Fruit實(shí)例的形式出現(xiàn)。
關(guān)于Enum為什么會(huì)有多態(tài)大概也就這么點(diǎn)貓膩了,那我們來考慮一下它有多大價(jià)值吧?
我們或許可以利用這一點(diǎn)來改造Strategy模式,傳統(tǒng)的Strategy會(huì)產(chǎn)生出稍微多一些的父類、子類,而如果用Enum的話,“一個(gè)類”(對(duì)程序作者來講)就能搞定,能簡(jiǎn)化一下類層次,再說了,用枚舉來表示區(qū)分各種不同策略也是很合情理的,所以,Java Enum的這點(diǎn)小小特性感覺還是比較有前途發(fā)揮一些作用的,起碼在代碼組織上;
更多應(yīng)用可能或是局限性就還需要逐步在實(shí)際應(yīng)用中摸索。
不過還是先看看“現(xiàn)象”吧:
public enum Fruit {
APPLE, PEAR, PEACH, ORANGE;
}
以上是一個(gè)簡(jiǎn)單的enum,關(guān)于它,我要補(bǔ)充一點(diǎn):
Fruit是java.lang.Enum的 子類 ,準(zhǔn)確地說,是Enum<Fruit>的子類,這里出現(xiàn)了一個(gè)繼承關(guān)系,不過這個(gè)繼承是編譯器幫我們做的,我們不能顯式地去做。不信的話我們可以試著用一個(gè)Enum<Fruit>的引用去指向一個(gè)APPLE,肯定是沒問題的,我就不再試了。
為了更直觀地說明這一點(diǎn),我們來看看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的實(shí)現(xiàn)也不過就是沿襲了Effective Java中提出的TypeSafeEnum模式,只不過是在編譯器和JVM等更底層的級(jí)別上提供了支持。
至此,至少說明了Fruit和Enum的繼承關(guān)系,但問題是: 現(xiàn)在不能繼續(xù)再從Fruit派生子類,那么哪來的多態(tài)呢?
還是再多寫點(diǎn)代碼吧:
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()方法;
我們?cè)谥骱瘮?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覆蓋了從父類繼承過來的默認(rèn)行為,而未從新定義test方法的ORANGE卻沿襲了父類的行為,多態(tài)性在這里展現(xiàn)出來了。
那么我們剛才明明看見過Fruit的反編譯結(jié)果,沒有任何新類繼承自Fruit,那么這些多態(tài)行為是哪里冒出來的呢?說它是“多態(tài)”是否準(zhǔn)確呢?
其實(shí),F(xiàn)ruit類在這個(gè)時(shí)候已經(jīng)發(fā)生了微妙的變化,一切都與JDK的Enum的實(shí)現(xiàn)有關(guān),我們現(xiàn)在可以到編譯結(jié)果目錄下面看看:
怎么除了Fruit.class之外,還多了幾個(gè)貌似是內(nèi)部類的class文件??也許看到這里我們能有點(diǎn)線索了,不過還是在這個(gè)時(shí)候在看看反編譯結(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);
這個(gè)時(shí)候的APPLE,PEAR,PEACH已經(jīng)以匿名內(nèi)部類的方式對(duì)Fruit進(jìn)行了Overide,自然體現(xiàn)出了多態(tài),多出的那三個(gè)疑似內(nèi)部類的class文件也就是它們!而ORANGE,沒有重寫test方法,仍然以一個(gè)Fruit實(shí)例的形式出現(xiàn)。
關(guān)于Enum為什么會(huì)有多態(tài)大概也就這么點(diǎn)貓膩了,那我們來考慮一下它有多大價(jià)值吧?
我們或許可以利用這一點(diǎn)來改造Strategy模式,傳統(tǒng)的Strategy會(huì)產(chǎn)生出稍微多一些的父類、子類,而如果用Enum的話,“一個(gè)類”(對(duì)程序作者來講)就能搞定,能簡(jiǎn)化一下類層次,再說了,用枚舉來表示區(qū)分各種不同策略也是很合情理的,所以,Java Enum的這點(diǎn)小小特性感覺還是比較有前途發(fā)揮一些作用的,起碼在代碼組織上;
更多應(yīng)用可能或是局限性就還需要逐步在實(shí)際應(yīng)用中摸索。
更多文章、技術(shù)交流、商務(wù)合作、聯(lián)系博主
微信掃碼或搜索:z360901061
微信掃一掃加我為好友
QQ號(hào)聯(lián)系: 360901061
您的支持是博主寫作最大的動(dòng)力,如果您喜歡我的文章,感覺我的文章對(duì)您有幫助,請(qǐng)用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點(diǎn)擊下面給點(diǎn)支持吧,站長(zhǎng)非常感激您!手機(jī)微信長(zhǎng)按不能支付解決辦法:請(qǐng)將微信支付二維碼保存到相冊(cè),切換到微信,然后點(diǎn)擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對(duì)您有幫助就好】元

