我正在学习 Oracle Java 教程。我目前正在学习泛型,我对类(class)末尾的问题 8 感到困惑,下面提供了解决方案。
具体来说,我不明白 T
背后的基本原理扩展 Object
和 Comparable<? super T>
. T
还不够吗?简单地扩展 Comparable<? super T>
,有什么优势T
扩展Object
还有吗?
问题:
编写一个通用方法来查找列表范围 [begin, end) 中的最大元素。
回答:
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;
}
}
我能找到拥有 <T extends Object & Comparable<? super T>
的唯一原因,而不是 T extends Comparable<? super T>
, 是为了在生成方法时向后兼容。
根据 Angelika Langer 的 Java Generics FAQ :
Occasionally, one must pay attention to the fact that a generification might change the signature of some methods in the byte code. Changing the signature will break existing code that cannot be recompiled and relies on the binary compatibility of the old and new version of the .class file.
在这种情况下,Java 自己的 Collections.max
用于返回 Object
1.5之前,泛型的到来。泛型化时,可以在没有 extends Object
的情况下声明此方法,它会在隔离状态下正常工作。
public static <T extends Comparable<? super T>> T max(Collection <? extends T> coll)
但是,出于字节码目的,删除此方法会使此方法返回 Comparable
, 而不是 Object
,这是向后不兼容。
要解决此问题,extends Object
被作为第一个边界插入,因此此方法的返回类型的删除将保留 Object
.
这解决了 1.5 中 Java 泛型的向后不兼容问题。
然而,教程中的问题指出:
Write a generic method to find the maximal element in the range [begin, end)
of a list.
您正在编写自己的新方法,因此尚无向后兼容性需要维护。 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
}