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

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

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

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

注意这几行:

  1. public static final Fruit APPLE;
  2. public static final Fruit PEAR;
  3. public static final Fruit PEACH;
  4. public static final Fruit ORANGE;

看来JDK Enum的实现也不过就是沿袭了Effective Java中提出的TypeSafeEnum模式,只不过是在编译器和JVM等更底层的级别上提供了支持。 

至此,至少说明了Fruit和Enum的继承关系,但问题是:现在不能继续再从Fruit派生子类,那么哪来的多态呢? 

还是再多写点代码吧:

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

其中,只有Orange没有Overide test()方法; 
我们在主函数中调用它们:

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

输出结果:

引用
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文件??也许看到这里我们能有点线索了,不过还是在这个时候在看看反编译结果吧,看看它到底在搞什么鬼:

  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. package test;
  6. import java.io.PrintStream;
  7. public class Fruit extends Enum
  8. {
  9. private Fruit(String s, int i)
  10. {
  11. super(s, i);
  12. }
  13. public void test()
  14. {
  15. System.out.println("I am a fruit.");
  16. }
  17. public static Fruit[] values()
  18. {
  19. Fruit afruit[];
  20. int i;
  21. Fruit afruit1[];
  22. System.arraycopy(afruit = ENUM$VALUES, 0, afruit1 = new Fruit[i = afruit.length], 0, i);
  23. return afruit1;
  24. }
  25. public static Fruit valueOf(String s)
  26. {
  27. return (Fruit)Enum.valueOf(test/Fruit, s);
  28. }
  29. Fruit(String s, int i, Fruit fruit)
  30. {
  31. this(s, i);
  32. }
  33. public static final Fruit APPLE;
  34. public static final Fruit PEAR;
  35. public static final Fruit PEACH;
  36. public static final Fruit ORANGE;
  37. private static final Fruit ENUM$VALUES[];
  38. static
  39. {
  40. APPLE = new Fruit("APPLE", 0) {
  41. public void test()
  42. {
  43. System.out.println("I am an apple.");
  44. }
  45. };
  46. PEAR = new Fruit("PEAR", 1) {
  47. public void test()
  48. {
  49. System.out.println("I am a pear.");
  50. }
  51. };
  52. PEACH = new Fruit("PEACH", 2) {
  53. public void test()
  54. {
  55. System.out.println("I am a peach.");
  56. }
  57. };
  58. ORANGE = new Fruit("ORANGE", 3);
  59. ENUM$VALUES = (new Fruit[] {
  60. APPLE, PEAR, PEACH, ORANGE
  61. });
  62. }
  63. }

注意这段代码:

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

这个时候的APPLE,PEAR,PEACH已经以匿名内部类的方式对Fruit进行了Overide,自然体现出了多态,多出的那三个疑似内部类的class文件也就是它们!而ORANGE,没有重写test方法,仍然以一个Fruit实例的形式出现。 

关于Enum为什么会有多态大概也就这么点猫腻了,那我们来考虑一下它有多大价值吧? 

我们或许可以利用这一点来改造Strategy模式,传统的Strategy会产生出稍微多一些的父类、子类,而如果用Enum的话,“一个类”(对程序作者来讲)就能搞定,能简化一下类层次,再说了,用枚举来表示区分各种不同策略也是很合情理的,所以,Java Enum的这点小小特性感觉还是比较有前途发挥一些作用的,起码在代码组织上; 
更多应用可能或是局限性就还需要逐步在实际应用中摸索。

java enum的更多相关文章

  1. Java Enum用法详解

    Java Enum用法详解 用法一:常量 在JDK1.5 之前,我们定义常量都是: public static fianl.... .现在好了,有了枚举,可以把相关的常量分组到一个枚举类型里,而且枚举 ...

  2. 如何使用Java Enum

    简单的用法:JavaEnum简单的用法一般用于代表一组常用常量,可用来代表一类相同类型的常量值.如: 性别: public enum SexEnum { male, female; } 颜色: pub ...

  3. (转)java enum枚举

    转载自: 原理:http://singleant.iteye.com/blog/686349 应用:http://www.cnblogs.com/happyPawpaw/archive/2013/04 ...

  4. java enum naming rules & Pascal case, Camel case, Uppercase

    java enum naming rules Constant & all Capital Case https://stackoverflow.com/questions/3069743/c ...

  5. Java Enum的多态性

    转载自:http://pf-miles.iteye.com/blog/187155 Enum+多态,我没说错,不过Enum是不可以被继承的,也不可以继承自别人,只是能实现接口而已,何谈多态?不过还是先 ...

  6. The Java Enum: A Singleton Pattern [reproduced]

    The singleton pattern restricts the instantiation of a class to one object. In Java, to enforce this ...

  7. 【转】Java enum的用法详解

    用法一:常量 在JDK1.5 之前,我们定义常量都是: public static fianl.... .现在好了,有了枚举,可以把相关的常量分组到一个枚举类型里,而且枚举提供了比常量更多的方法. p ...

  8. Java enum的用法详解[转]

    Ref:http://www.cnblogs.com/happyPawpaw/archive/2013/04/09/3009553.html 用法一:常量 在JDK1.5 之前,我们定义常量都是: p ...

  9. Java enum的用法详解

    (转自:http://www.cnblogs.com/happyPawpaw/archive/2013/04/09/3009553.html) 用法一:常量 在JDK1.5 之前,我们定义常量都是: ...

随机推荐

  1. Reactor 模式的简单实现

    Reactor 模式简单实现 在网上有部分文章在描述Netty时,会提到Reactor.这个Reactor到底是什么呢?为了搞清楚Reactor到底是什么鬼,我写了一个简单的Demo,来帮助大家理解他 ...

  2. OSI七层模型详解 TCP/IP协议

      总结 OSI中的层 功能 TCP/IP协议族 应用层 文件传输,电子邮件,文件服务,虚拟终端 TFTP,HTTP,SNMP,FTP,SMTP,DNS,Telnet 等等 表示层 数据格式化,代码转 ...

  3. [译]Thinking in React

    编者按 使用React的思想来构建应用对我在实际项目中以及帮助他人解决实际问题时起到了很大作用,所以我翻译此文来向那些正在或即将陷入React或React-Native深坑的同胞们表示慰问.网上已经有 ...

  4. 树莓派debian配置lamp【解决apache不显示php】

      Apache + MySql + Php. 1.安装Apache Apache可以用下面的命令来安装 sudo apt-get install apache2 Apache默认路径是/var/ww ...

  5. spring 事务回滚

    1.遇到的问题 当我们一个方法里面有多个数据库保存操作的时候,中间的数据库操作发生的错误.伪代码如下: public method() { Dao1.save(Person1); Dao1.save( ...

  6. Python 字符串相加问题

    今天在用Python拼接字符串时碰到个问题,从数据库取出来的数据以及获取到的时间等数据拼成了一个字符串a,将字符串a与自定义的字符串b拼接时一直中断,无法继续执行,也没有报错,将数据库取出数据变成自定 ...

  7. [AR]Vumark(下一代条形码)

    VuMark 准备知识 Vumark的说明: https://library.vuforia.com/articles/Training/VuMark https://library.vuforia. ...

  8. 异步方法的意义何在,Async和await以及Task的爱恨情仇,还有多线程那一家子。

    前两天刚感受了下泛型接口的in和out,昨天就开始感受神奇的异步方法Async/await,当然顺路也看了眼多线程那几个.其实多线程异步相关的类单个用法和理解都不算困难,但是异步方法Async/awa ...

  9. 【记录】Ubuntu下安装VirtualBox

    之前换了新硬盘,重装了ubuntu,由于学习需要还是要装个虚拟机.以前用过VMWare真的是神卡,这次换VirtualBox,希望开源社区能给我带来曙光:) 添加VirtualBox的源并安装5.1版 ...

  10. Linux文件操作的主要接口API及相关细节

    操作系统API: 1.API是一些函数,这些函数是由linux系统提供支持的,由应用层程序来使用,应用层程序通过调用API来调用操作系统中的各种功能,来干活 文件操作的一般步骤: 1.在linux系统 ...