Java的Enum的多态性

看到篇 “ 小谈Java Enum的多态性 ” 的帖子,觉着蛮有意思,转来看看,原文如下:

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

Java代码   收藏代码
  1. public enum Fruit {  
  2.     APPLE, PEAR, PEACH, ORANGE;  
  3. }  

以上是一个简单的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. }  

注意这几行: 
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;  

看来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. }  

其中,只有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.     }  

输出结果: 
引用
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. }  

注意这段代码: 
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);  

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

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

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

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
Java Enum 也可以和另一个 Enum 关联起来,这种情况下可以使用 EnumMap 或者 EnumSet。 1. EnumMap EnumMap 是一种特殊的 Map,它的 key 必须是 Enum 类型。可以用来将一个 Enum 和另一个 Enum 关联起来,例如: ```java public enum Weekday { MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY } public enum Weather { SUNNY, RAINY, CLOUDY, SNOWY } public class Example { private static final Map<Weekday, Weather> weatherMap = new EnumMap<>(Weekday.class); static { weatherMap.put(Weekday.MONDAY, Weather.SUNNY); weatherMap.put(Weekday.TUESDAY, Weather.CLOUDY); weatherMap.put(Weekday.WEDNESDAY, Weather.RAINY); weatherMap.put(Weekday.THURSDAY, Weather.SUNNY); weatherMap.put(Weekday.FRIDAY, Weather.SNOWY); weatherMap.put(Weekday.SATURDAY, Weather.CLOUDY); weatherMap.put(Weekday.SUNDAY, Weather.RAINY); } public static void main(String[] args) { System.out.println(weatherMap.get(Weekday.MONDAY)); // SUNNY } } ``` 在上面的例子中,我们使用 EnumMap 将 Weekday 枚举和 Weather 枚举关联起来。 2. EnumSet EnumSet 是一种特殊的 Set,它的元素必须是 Enum 类型。可以用来将一个 Enum 和另一个 Enum 关联起来,例如: ```java public enum Weekday { MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY } public enum Weekend { SATURDAY, SUNDAY } public class Example { private static final Set<Weekday> weekdays = EnumSet.of( Weekday.MONDAY, Weekday.TUESDAY, Weekday.WEDNESDAY, Weekday.THURSDAY, Weekday.FRIDAY ); public static void main(String[] args) { System.out.println(weekdays.contains(Weekday.MONDAY)); // true System.out.println(weekdays.contains(Weekday.SATURDAY)); // false } } ``` 在上面的例子中,我们使用 EnumSet 将 Weekday 枚举和 Weekend 枚举关联起来,将工作日和周末分别加入不同的 EnumSet 中。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值