小谈Java Enum的多态性

转载自: http://pf-miles.iteye.com/blog/187155

  Enum+多态,我没说错,不过Enum是不可以被继承的,也不可以继承自别人,只是能实现接口而已,何谈多态?
不过还是先看看“现象”吧:

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

  以上是一个简单的enum,关于它,我要补充一点: Fruit是java.lang.Enum的子类,准确地说,是Enum的子类,这里出现了一个继承关系,不过这个继承是编译器帮我们做的,我们不能显式地去做。不信的话我们可以试着用一个Enum的引用去指向一个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.

  可以看到,重新定义了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的这点小小特性感觉还是比较有前途发挥一些作用的,起码在代码组织上;

  更多应用可能或是局限性就还需要逐步在实际应用中摸索。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值