小談Java Enum的多態性

Enum+多態,我沒說錯,不過Enum是不能夠被繼承的,也不能夠繼承自別人,只是能實現接口而已,何談多態? 
不過仍是先看看「現象」吧: 
html

Java代碼  收藏代碼java

  1. public enum Fruit {  
        APPLE, PEAR, PEACH, ORANGE;  
    }


以上是一個簡單的enum,關於它,我要補充一點: 
Fruit是java.lang.Enum的子類,準確地說,是Enum<Fruit>的子類,這裏出現了一個繼承關係,不過這個繼承是編譯器幫咱們作的,咱們不能顯式地去作。不信的話咱們能夠試着用一個Enum<Fruit>的引用去指向一個APPLE,確定是沒問題的,我就再也不試了。 
爲了更直觀地說明這一點,咱們來看看Fruit的反編譯結果吧: 
app

Java代碼  收藏代碼ide

  1.  

  2. 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  
            });  
        }  
    }


注意這幾行: 
函數

Java代碼  收藏代碼ui

  1. 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

Java代碼  收藏代碼spa

  1. 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

Java代碼  收藏代碼htm

  1. 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文件??也許看到這裏咱們能有點線索了,不過仍是在這個時候在看看反編譯結果吧,看看它到底在搞什麼鬼: 

Java代碼  收藏代碼

  1. // 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  
            });  
        }  
    }


注意這段代碼: 

Java代碼  收藏代碼

  1. 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的這點小小特性感受仍是比較有前途發揮一些做用的,起碼在代碼組織上;
更多應用可能或是侷限性就還須要逐步在實際應用中摸索。

相關文章
相關標籤/搜索