come from http://www.it165.net/pro/html/201305/5643.html

  • public abstract class Enum<E extends Enum<E>>
    extends Object
    implements Comparable<E>, Serializable

    为什么 Enum 类需要使用如下这么奇怪的泛型,<E extends Enum<E>>,初次看真是让我晕了, E 到底代表什么啊?为什么不定义成 public abstract class Enum extends Object 呢?很容易找到答案,Enum 需要实现Comparable 比较接口。

    那似乎也可以定义成 public abstract class Enum<E>extends Object implements Comparable<E>, Serializable 。仔细想,就会发现会有问题,Comparable 的compareTo()方法是这样的: public final int compareTo(E o),我们肯定不希望这个 E 是任何类型的,而是希望这个E 是 Enum 类型的,同时我们不希望两个不同的 Enum 子类实例可以进行比较(没有意义),即我们最希望的是同一个 Enum 子类的实例进行比较。
     
    下面 的 EnumClass.java 摘自 《Thinking in java 》第19章枚举类型,稍微修改了下。通过 javap javap Shrubbery 反编译,可以看到 Shrubbery 是一个继承自 Enum 的类。


     

    01.Compiled from "EnumClass.java"
    02.final class enumerated.Shrubbery extends java.lang.Enum{
    03.public static final enumerated.Shrubbery GROUND;
    04.public static final enumerated.Shrubbery CRAWLING;
    05.public static final enumerated.Shrubbery HANGING;
    06.static {};
    07.public static enumerated.Shrubbery[] values();
    08.public static enumerated.Shrubbery valueOf(java.lang.String);
    09.}

    由于擦除的原因, enum Shrubbery {} 实事上等价于 final class Shrubbery extends Enum<Shrubbery>(即告诉编译器Shrubbery 继承于 Enum,而这个Enum 的泛型参数就是 Shrubbery 自身)。现在我们检查下,Shrubbery 符不符合 <E extends Enum<E>> 形式,如果你还看不明白,可以把 E 替换成Shrubbery ,你可以看到这就是 Shrubbery 的类定义,所以Shrubbery 完全符合要求!另外编译加上 final 修饰的原因是不希望 Enum 的子类可以作为父类被其它类继承。

     

    01.//: enumerated/EnumClass.java
    02.// Capabilities of the Enum class
    03.package enumerated;
    04.import static net.mindview.util.Print.*;
    05. 
    06.enum Shrubbery { GROUND, CRAWLING, HANGING }
    07. 
    08.// 错误无法继承
    09.//enum ShrubberySub extends Shrubbery {};
    10.enum AnotherShrubbery{GROUND, CRAWLING, HANGING }
    11. 
    12.public class EnumClass {
    13.public static void main(String[] args) {
    14.for(Shrubbery s : Shrubbery.values()) {
    15.print(s + " ordinal: " + s.ordinal());
    16.printnb(s.compareTo(Shrubbery.CRAWLING) + " ");
    17.printnb(s.equals(Shrubbery.CRAWLING) + " ");
    18.print(s == Shrubbery.CRAWLING);
    19.print(s.getDeclaringClass());
    20.print(s.name());
    21.print("----------------------");
    22.}
    23.// Produce an enum value from a string name:
    24.for(String s : "HANGING CRAWLING GROUND".split(" ")) {
    25.Shrubbery shrub = Enum.valueOf(Shrubbery.class, s);
    26.print(shrub);
    27.}
    28. 
    29.// 编译不过,在不同 enum 类型中进行比较
    30.Shrubbery.GROUND.compareTo(AnotherShrubbery.GROUND);
    31.}
    32.}

    为了验证上面的推出的结果,我写了下面手机类来进行测试。同类手机可以进行系统版本号的比较,不同类的手机系统版本号比较没有意义。通过 E extends Handphone<E> 的泛型限定,我们就可以阻止编译器在 Iphone 和 Android 手机之间进行系统版本号的比较。 www.it165.net

    01.//: generics/WeirdGenerics.java
    02.// 怪异的泛型
    03.package generics;
    04. 
    05.abstract class Handphone<E extends Handphone<E>> implements Comparable<E>{
    06.public abstract int osVersion();
    07.public int compareTo(E o){
    08.return osVersion() - o.osVersion();
    09.}
    10.}
    11. 
    12.class Iphone extends Handphone<Iphone>{
    13.private int version;
    14.public Iphone(int version){
    15.this.version = version;
    16.}
    17.public int osVersion(){
    18.return version;
    19.}
    20.}
    21. 
    22.class <a href="http://www.it165.net/pro/ydad/" target="_blank" class="keylink">Android</a> extends Handphone<Android>{
    23.private int version;
    24.public Android(int version){
    25.this.version = version;
    26.}
    27.public int osVersion(){
    28.return version;
    29.}
    30.}
    31. 
    32.public class WeirdGenerics{
    33.public static void main(String []args){
    34.Iphone i4 = new Iphone(4), i5 = new Iphone(5);
    35.Android a2 = new Android(2), a3 = new Android(3);
    36. 
    37.System.out.println(i5.compareTo(i4));
    38.System.out.println(a3.compareTo(a2));
    39.// 错误,两种手机之间不能比较系统版本大小
    40.//System.out.println(i5.compareTo(a3));
    41.}
    42.}