以下兩行有什麼區別?Java通用方法邊界
public static <T extends Comparable<? super T>> int methodX(List<T> data)
public static <T> int methodX(List<? extends Comparable<? super T>> data)
以下兩行有什麼區別?Java通用方法邊界
public static <T extends Comparable<? super T>> int methodX(List<T> data)
public static <T> int methodX(List<? extends Comparable<? super T>> data)
你的第一個選項是「嚴格的」參數化。意思是說,你正在用一堆限制來定義類T
,然後在List
之後使用它。在第二種方法中,參數類T
是通用的,沒有條件,而List
的類參數是根據參數T
定義的。
第二種方式是語法不同,以及,用?
,而不是第一個選項的T
,因爲在參數定義你是不是定義的類型參數T
而是使用它,所以第二個方法不能作爲具體。
出現這種實際差異是繼承之一。你的第一種方法需要一個類型,它相當於一個超類本身,而第二種類型僅需媲美無條件/無關T
:
public class Person implements Comparable<Number> {
@Override
public int compareTo(Number o) {
return 0;
}
public static <T extends Comparable<? super T>> int methodX(List<T> data) {
return 0;
}
public static <T> int methodY(List<? extends Comparable<? super T>> data) {
return 0;
}
public static void main(String[] args) {
methodX(new ArrayList<Person>()); // stricter ==> compilation error
methodY<Object>(new ArrayList<Person>());
}
}
如果更改的Comparable
Person
能夠比較Object
或Person
(基類的繼承樹),那麼methodX
也將工作。
第一種方法預計其可以對他們自己的類或它的超類型進行比較的元素的列表。再說了,實數可以與任何類型的數字:
class Real extends Number implements Comparable<Number> {
public int compareTo(Number o) ...
}
有點更加嚴格,但對於你的第一個方法還是可以接受的是:
class Real extends Number implements Comparable<Real> {
public int compareTo(Real o) ...
}
但第二種方法實際上是不從這個版本非常不同:
public static int methodY(List<? extends Comparable<?>> data) ...
也就是說,你可以用一個無名通配符?
更換T
,因爲它只是用來一次在方法簽名中。它不使用的概念,如同一類或對象的自己的類等
給市民,第二個版本是大致相當於
public static <T, X extends Comparable<? super T>> int methodX(List<X> data)
假設呼叫者與ARG其具體類型List<Foo>
調用它。類型推斷會得出結論X=Foo
。然後我們得到約T A新方程從X
的結合
=>
Foo <: Comparable<? super T>
(A <: B
裝置A是B的子類型)
如果Foo
是可比可言,幾乎可以肯定implements Comparable<Foo>
[2]
=>
Comparable<Foo> <: Comparable<? super T>
=>
T <: Foo
沒有進一步的信息,推論選擇T=Foo
。
因此,從呼叫者的POV,這兩個版本並沒有真正的不同。
在方法體內部,第二個版本不能訪問類型參數X
,它是編譯階段引入的一個綜合參數。這意味着您只能從data
中讀取。諸如
X x = data.get(0);
data.set(1, x);
在版本#2中是不可能的;版本#1中沒有這樣的問題,T
。
但是我們可以轉發#2#1
<T1> method1(List<T1> data){ data.set(...); }
<T2> method2(List<?...> data)
{
method1(data);
}
(they must have difference method names; overloading not allowed since java7)
這是因爲編譯器的data
類型是真的List<X>
(它知道的祕密X
),所以沒有問題推斷後調用method1(data)
該T1=X
[1] JLS3,5.1.10捕獲轉換
[2]根據的Comparable
的Javadoc ,該接口對每個實現它的類的對象進行總排序。這意味着如果Foo implements Comparable<W>
,W必須是Foo或超級類型的Foo。對於一個子類實現來說,定義一個超類的對象之間的全部順序是相當不可能的。所以W
絕對應該是Foo
。否則有趣的事情會發生。臭名昭着的例子是'Timestamp',它的javadoc(現在)解釋了爲什麼它不能與其超類型相比較Date