`

小谈java Enum的多态

    博客分类:
  • J2SE
阅读更多
Enum+多态,我没说错,不过Enum是不可以被继承的,也不可以继承自别人,只是能实现接口而已,何谈多态?
不过还是先看看“现象”吧:
Java代码

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

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


以上是一个简单的enum,关于它,我要补充一点:
Fruit是java.lang.Enum的子类,准确地说,是Enum<Fruit>的子类,这里出现了一个继承关系,不过这个继承是编译器帮我们做的,我们不能显式地去做。不信的话我们可以试着用一个Enum<Fruit>的引用去指向一个APPLE,肯定是没问题的,我就不再试了。
为了更直观地说明这一点,我们来看看Fruit的反编译结果吧:
Java代码

   1. package test; 
   2.  
   3.  
   4. public final class Fruit extends Enum 
   5. { 
   6.  
   7.     private Fruit(String s, int i) 
   8.     { 
   9.         super(s, i); 
  10.     } 
  11.  
  12.     public static Fruit[] values() 
  13.     { 
  14.         Fruit afruit[]; 
  15.         int i; 
  16.         Fruit afruit1[]; 
  17.         System.arraycopy(afruit = ENUM$VALUES, 0, afruit1 = new Fruit[i = afruit.length], 0, i); 
  18.         return afruit1; 
  19.     } 
  20.  
  21.     public static Fruit valueOf(String s) 
  22.     { 
  23.         return (Fruit)Enum.valueOf(test/Fruit, s); 
  24.     } 
  25.  
  26.     public static final Fruit APPLE; 
  27.     public static final Fruit PEAR; 
  28.     public static final Fruit PEACH; 
  29.     public static final Fruit ORANGE; 
  30.     private static final Fruit ENUM$VALUES[]; 
  31.  
  32.     static  
  33.     { 
  34.         APPLE = new Fruit("APPLE", 0); 
  35.         PEAR = new Fruit("PEAR", 1); 
  36.         PEACH = new Fruit("PEACH", 2); 
  37.         ORANGE = new Fruit("ORANGE", 3); 
  38.         ENUM$VALUES = (new Fruit[] { 
  39.             APPLE, PEAR, PEACH, ORANGE 
  40.         }); 
  41.     } 
  42. } 

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代码

   1. public static final Fruit APPLE; 
   2.     public static final Fruit PEAR; 
   3.     public static final Fruit PEACH; 
   4.     public static final Fruit 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派生子类,那么哪来的多态呢?

还是再多写点代码吧:
Java代码

   1. public enum Fruit { 
   2.     APPLE { 
   3.  
   4.         public void test() { 
   5.             System.out.println("I am an apple."); 
   6.         } 
   7.     }, 
   8.     PEAR { 
   9.  
  10.         public void test() { 
  11.             System.out.println("I am a pear."); 
  12.         } 
  13.     }, 
  14.     PEACH { 
  15.  
  16.         public void test() { 
  17.             System.out.println("I am a peach."); 
  18.         } 
  19.     }, 
  20.     ORANGE; 
  21.  
  22.     public void test() { 
  23.         System.out.println("I am a fruit."); 
  24.     } 
  25. } 

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()方法;
我们在主函数中调用它们:
Java代码

   1. public static void main(String[] args) { 
   2.         Fruit.APPLE.test(); 
   3.         Fruit.PEAR.test(); 
   4.         Fruit.PEACH.test(); 
   5.         Fruit.ORANGE.test(); 
   6.     } 

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. 
   2. // Jad home page: http://www.geocities.com/kpdus/jad.html 
   3. // Decompiler options: packimports(3)  
   4. // Source File Name:   Fruit.java 
   5.  
   6. package test; 
   7.  
   8. import java.io.PrintStream; 
   9.  
  10. public class Fruit extends Enum 
  11. { 
  12.  
  13.     private Fruit(String s, int i) 
  14.     { 
  15.         super(s, i); 
  16.     } 
  17.  
  18.     public void test() 
  19.     { 
  20.         System.out.println("I am a fruit."); 
  21.     } 
  22.  
  23.     public static Fruit[] values() 
  24.     { 
  25.         Fruit afruit[]; 
  26.         int i; 
  27.         Fruit afruit1[]; 
  28.         System.arraycopy(afruit = ENUM$VALUES, 0, afruit1 = new Fruit[i = afruit.length], 0, i); 
  29.         return afruit1; 
  30.     } 
  31.  
  32.     public static Fruit valueOf(String s) 
  33.     { 
  34.         return (Fruit)Enum.valueOf(test/Fruit, s); 
  35.     } 
  36.  
  37.     Fruit(String s, int i, Fruit fruit) 
  38.     { 
  39.         this(s, i); 
  40.     } 
  41.  
  42.     public static final Fruit APPLE; 
  43.     public static final Fruit PEAR; 
  44.     public static final Fruit PEACH; 
  45.     public static final Fruit ORANGE; 
  46.     private static final Fruit ENUM$VALUES[]; 
  47.  
  48.     static  
  49.     { 
  50.         APPLE = new Fruit("APPLE", 0) { 
  51.  
  52.             public void test() 
  53.             { 
  54.                 System.out.println("I am an apple."); 
  55.             } 
  56.  
  57.         }; 
  58.         PEAR = new Fruit("PEAR", 1) { 
  59.  
  60.             public void test() 
  61.             { 
  62.                 System.out.println("I am a pear."); 
  63.             } 
  64.  
  65.         }; 
  66.         PEACH = new Fruit("PEACH", 2) { 
  67.  
  68.             public void test() 
  69.             { 
  70.                 System.out.println("I am a peach."); 
  71.             } 
  72.  
  73.         }; 
  74.         ORANGE = new Fruit("ORANGE", 3); 
  75.         ENUM$VALUES = (new Fruit[] { 
  76.             APPLE, PEAR, PEACH, ORANGE 
  77.         }); 
  78.     } 
  79. } 

// 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  
   2.     { 
   3.         APPLE = new Fruit("APPLE", 0) { 
   4.  
   5.             public void test() 
   6.             { 
   7.                 System.out.println("I am an apple."); 
   8.             } 
   9.  
  10.         }; 
  11.         PEAR = new Fruit("PEAR", 1) { 
  12.  
  13.             public void test() 
  14.             { 
  15.                 System.out.println("I am a pear."); 
  16.             } 
  17.  
  18.         }; 
  19.         PEACH = new Fruit("PEACH", 2) { 
  20.  
  21.             public void test() 
  22.             { 
  23.                 System.out.println("I am a peach."); 
  24.             } 
  25.  
  26.         }; 
  27.         ORANGE = new Fruit("ORANGE", 3); 

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的这点小小特性感觉还是比较有前途发挥一些作用的,起码在代码组织上;
更多应用可能或是局限性就还需要逐步在实际应用中摸索。

转自:http://pf-miles.iteye.com/blog/187155
分享到:
评论

相关推荐

    Java基础知识点总结.docx

    Java数组与集合小结 305 递归 309 对象的序列化 310 Java两种线程类:Thread和Runnable 315 Java锁小结 321 java.util.concurrent.locks包下常用的类 326 NIO(New IO) 327 volatile详解 337 Java 8新特性 347 Java...

    Java JDK 7学习笔记(国内第一本Java 7,前期版本累计销量5万册)

    16.2.1 了解java.lang.enum类 533 16.3 关于注释 542 16.3.1 常用标准注释 542 16.3.2 自定义注释类型 545 16.3.3 执行时期读取注释信息 549 16.4 重点复习 551 16.5 课后练习 551 appendixa 如何...

    java语言程序设计 java编程笔记 由浅入深的笔记 共32份 全套资源.rar

    【完整课程列表】 ...封装和继承以及多态部分.docx 接口和抽象类以及实现类.docx 枚举enum.docx 设计模式.docx 数组.docx 网络编程.docx 线程和内部类.docx 循环和类对象.docx 异常.docx 正则表达式.docx 总结.docx

    \java超强笔记(超级经典)

    全部是txt格式的,容量小,以下内容为其中之一: 5.0新特性: 泛型: 泛型的形式: 类型&gt; &lt;E extends Numner&comparator&gt; 类名&接口,表示E继承Numner类实现comparator接口 &lt;?&gt; 泛型通配符表示任意...

    整理后java开发全套达内学习笔记(含练习)

    polymiorphism[java] 多态 (polymorphism 多形性[,pɒli'mɒ:fizm]) allowing a single object to be seen as having many types. principle n.原则,原理,主义 ['prinsipl] priority n. 优先级 [prai'ɒriti] ...

    JAVA面向对象详细资料

    Java面向对象 1 1 学习方法与要求 1 2 面向对象语言与面向过程语言的区别 7 3 面向对象?什么对象? 8 4 什么是类? 9 5 如何创建一个类Class? 10 6 如何使用类创建对象 10 7 引用与实例 11 8 实例属性与实例方法 ...

    Java开发技术大全 电子版

    1.4一个简单的Java小程序16 1.5本章小结18 第2章Java语言基础19 2.1Java语言的特点19 2.2Java程序的构成21 2.3数据类 型23 2.3.1基本数据类型23 2.3.2常量25 2.3.3变量26 2.3.4整型数据27 .2.3.5浮点型...

    EE-Bootcamp-FragilityExample:2015年7月26日在Equal Experts Pune Bootcamp上执行的易碎性示例

    在会议期间,我们决定使用多态行为以演示Java enum的功能。 将enum Expense.Type替换为将从配置中填充的数据类。 将源文件拆分为单独的文件。 将ExpenseReportPrinter分成两个类,因为它仍然违反SRP。 当前,它...

    C++大学教程,一本适合初学者的入门教材(part2)

    1.9 Java、Internet与万维网 1.10 其他高级语言 1.11 结构化编程 1.12 典型C++环境基础 1.13 C++与本书的一般说明 1.14 C++编程简介 1.15 简单程序:打印一行文本 1.16 简单程序:两个整数相加 1.17 内存的...

    C++编程思想 (作者学习C++亲身体会及多年教学经验)

    全书共分十八章,内容涉及对象的演化、数据抽象、隐藏实现、初始化与清除、函数重载与缺省参数、输入输出流介绍、常量、内联函数、命名控制、引用和拷贝构造函数、运算符重载、动态对象创建、继承和组合、多态和虚...

    C++编程思想1-5 清晰PDF

    全书共分十八章,内容涉及对象的演化、数据抽象、隐藏实现、初始化与清除、函数重载与缺省参数、输入输出流介绍、常量、内联函数、命名控制、引用和拷贝构造函数、运算符重载、动态对象创建、继承和组合、多态和虚...

    C++编程思想(中文版)

    全书共分十八章,内容涉及对象的演化、数据抽象、隐藏实现、初始化与清除、函数重载与缺省参数、输入输出流介绍、常量、内联函数、命名控制、引用和拷贝构造函数、运算符重载、动态对象创建、继承和组合、多态和虚...

    C++大学教程,一本适合初学者的入门教材(part1)

    1.9 Java、Internet与万维网 1.10 其他高级语言 1.11 结构化编程 1.12 典型C++环境基础 1.13 C++与本书的一般说明 1.14 C++编程简介 1.15 简单程序:打印一行文本 1.16 简单程序:两个整数相加 1.17 内存的...

    Hibernate注释大全收藏

    有缺点,如多态查询或关联。Hibernate 使用 SQL Union 查询来实现这种策略。 这种策略支持双向的一对多关联,但不支持 IDENTIFY 生成器策略,因为ID必须在多个表间共享。一旦使用就不能使用AUTO和IDENTIFY生成器。 ...

    在一小时内学会 C#(txt版本)

    和 C++ 一样,C# 是大小写敏感的。半角分号(;)是语句分隔符。和 C++ 有所区别的是,C# 中没有单独的声明(头)和实现(CPP)文件。所有代码(类声明和实现)都放在扩展名为 cs 的单一文件中。 看看 C# 中的 Hello...

    Effective C++ 中文版

     ·洞察 C++和其他语言(例如Java、C#、C)之间的不同。此举有助于那些来自其他语言阵营的开发人员消化吸收 C++ 式的各种解法。 目录: 译序 中英简繁术语对照 目录 序言 致谢 导读 1.让自己习惯C++ ...

    C++大学教程

    1.9 Java、Internet与万维网--------------------------------------------7 1.10 其它高级语言------------------------------------------------------8 1.11 结构化编程-----------------------------------...

Global site tag (gtag.js) - Google Analytics