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