考慮下面的代碼示例:執法在方法普通類型等式約束參數
@SafeVarargs
public static <U> Object[] sortedCopy(Comparator<? super U> comparator, U... values) {
U[] copy = Arrays.copyOf(values, values.length);
Arrays.sort(copy, comparator);
return copy; //copy is implicitly cast to Object[] -> no heap pollution
}
public static <U> Object[] sortedCopy(U... values) {
return sortedCopy(Comparator.naturalOrder(), values); //why does this compile???
}
我本來期望編譯器拒絕sortedCopy(U...)
線,具有以下的理由是:
的返回類型Comparator.naturalOrder()
是Comparator<T>
,其中T
是此方法的泛型類型參數,必須滿足約束T extends Comparable<? super T>
。由於該方法不接受任何參數,並且其在上述代碼中的調用沒有明確指定類型爲T
(如Comparator.<U>naturalOrder()
,由於U
未擴展Comparable
,因此Comparator.<U>naturalOrder()
無法編譯),因此必須以其他方式推斷出T
。我可以看到推斷T
的唯一方法是通過方法簽名sortedCopy(Comparator<? super U>, U...)
。編譯器知道values
的類型,因此可以推斷出U
,並且繼而可以推斷出邊界爲T
,即有界通配符? super U
。但是編譯器應該認識到,任何? super U
都不能滿足由Comparator.naturalOrder()
指定的T
的要求,即T extends Comparable<? super T>
,因爲U
本身不延伸Comparable<? super U>
,所以U
的任何超類都不能。
讓我感到困惑的是編輯器確實在將簽名從sortedCopy(U...)
更改爲sortedCopy(U[])
時生成錯誤。我想這與第二種情況有關,U
作爲數組的類型在運行時存在,而在第一種情況下,它不是。但我還是不明白爲什麼這將使問題的有效方法調用,這是因爲:
- 據我瞭解,一般類型的可變參數參數轉換爲
Object[]
如果值傳遞給方法因爲可變參數是通用的,因此是不可確定的類型,如果我理解正確,那麼在上面的代碼中就是這種情況,因爲sortedCopy(U...)
的U
是不可確定的。但即使如此,爲什麼編譯器沒有意識到Object
沒有擴展Comparable<? super Object>
? - 前面的參數討論運行時類型。但是,我們仍然是預編譯的,所以關於運行時類型的猜測甚至不應該在這種情況下相關,因爲儘管
U
在運行時可能不再存在,但編譯器仍然知道它,並且應該能夠檢查不管方法參數是一個數組還是一個可變參數,都會實現等式約束。
那麼,爲什麼上述代碼示例中的問題仍在編譯?
除此之外,如果方法sortedCopy(Comparator<? super U>, U...)
的@SafeVarargs
註釋不合適,我也將非常感謝您的反饋。我相信是這樣,但我對此沒有信心。
如果你改變了第二個方法的名字,很明顯第一個不是被'sortedCopy(Comparator.naturalOrder(),values)調用的' – Javier
@Javier:我不確定你要去哪裏。如果您更改方法的名稱,那麼不存在任何含糊之處。我的直覺就是保持意圖,並用泛型來糾正問題。 – Makoto
這只是另一種證明「不選擇比較器作爲第一個參數的重載參數」的方法。 OP提示'(比較器 super U>比較器,U ...值)'適用於實際參數'(Comparator.naturalOrder(),values)',但事實上並非如此。 – Javier