我正在通过Oracle java教程。我目前正在使用泛型,我在课程结束时对问题8感到困惑,下面提供了解决方法。
具体来说,我不理解T
延长Object
和Comparable<? super T>
背后的理由。仅T
只是扩展Comparable<? super T>
还不够,还有T
扩展Object
的优势吗?
问题:
编写一个通用方法来查找列表[开头,结尾]范围内的最大元素。
答案:
import java.util.*;
public final class Algorithm {
public static <T extends Object & Comparable<? super T>>
T max(List<? extends T> list, int begin, int end) {
T maxElem = list.get(begin);
for (++begin; begin < end; ++begin)
if (maxElem.compareTo(list.get(begin)) < 0)
maxElem = list.get(begin);
return maxElem;
}
}
答案 0 :(得分:1)
我可以找到<T extends Object & Comparable<? super T>
而不是T extends Comparable<? super T>
的唯一原因是在生成方法时向后兼容。
根据Angelika Langer的Java Generics FAQ:
有时候,必须注意一般化可能会改变字节代码中某些方法的签名这一事实。更改签名将破坏无法重新编译的现有代码,并依赖于旧版和新版.class文件的二进制兼容性。
在这种情况下,Java自己的Collections.max
曾经在1.5之前返回Object
,即泛型的到来。通用时,可以在没有extends Object
的情况下声明此方法,并且它可以在单独的情况下正常工作。
public static <T extends Comparable<? super T>> T max(Collection <? extends T> coll)
但是,出于字节码的目的,此方法的擦除使此方法返回Comparable
,而不是Object
,这是向后不兼容的。
要解决此问题,extends Object
作为第一个绑定被插入,因此此方法的返回类型的擦除将保持为Object
。
这解决了1.5中Java泛型的向后不兼容问题。
然而,教程中提出的问题是:
编写一个通用方法来查找列表
[begin, end)
范围内的最大元素。
您正在编写自己的新方法,因此尚无向后兼容性。
>在本教程问题的答案中extends Object
是不必要的。
另外
在字节码(javap -c Algorithm.class
)中,所有类型都经历类型擦除,甚至是局部变量maxElem
。
public static <T extends java.lang.Comparable<? super T>> T max(java.util.List<? extends T>, int, int);
Code:
0: aload_0
1: iload_1
2: invokeinterface #2, 2 // InterfaceMethod java/util/List.get:(I)Ljava/lang/Object;
get
方法已返回Object
。那么它如何在compareTo
中调用Comparable
?
7: astore_3
8: iinc 1, 1
11: iload_1
12: iload_2
13: if_icmpge 49
16: aload_3
17: checkcast #3 // class java/lang/Comparable
20: aload_0
21: iload_1
22: invokeinterface #2, 2 // InterfaceMethod java/util/List.get:(I)Ljava/lang/Object;
27: invokeinterface #4, 2 // InterfaceMethod java/lang/Comparable.compareTo:(Ljava/lang/Object;)I
编译器已向Comparable
插入隐式强制转换,以便可以调用compareTo
方法。它声称列表中的对象是Comparable
,因为第二个上限是Comparable<? super T>
。
32: ifge 43
35: aload_0
36: iload_1
37: invokeinterface #2, 2 // InterfaceMethod java/util/List.get:(I)Ljava/lang/Object;
42: astore_3
43: iinc 1, 1
46: goto 11
49: aload_3
50: areturn
}