[英]Java: Pass actual <T extends Event> class. (Generics Problems)
[英]Generics in Java Comparator class. What is the exact type of T and U?
考慮以下兩種方法。 它們唯一的區別在於它們的泛型類型聲明 Function<>
public static <T, U extends Comparable<? super U>> Comparator<T> comparing(
Function<? super T, ? extends U> keyExtractor)
{
Objects.requireNonNull(keyExtractor);
return (Comparator<T> & Serializable)
(c1, c2) -> keyExtractor.apply(c1).compareTo(keyExtractor.apply(c2));
}
public static <T, U extends Comparable<? super U>> Comparator<T> comparingT(
Function<T, ? extends U> keyExtractor) <-- Check here! T instead of ? super T
{
Objects.requireNonNull(keyExtractor);
return (Comparator<T> & Serializable)
(c1, c2) -> keyExtractor.apply(c1).compareTo(keyExtractor.apply(c2));
}
假設我有一個List<GamingComputer> = { ASUS, MSI }
,其中GamingComputer
擴展了Computer
。 現在,我想對它們進行排序。
List.sort( comparing( Computer::getProperty ) )
T的類型是什么?
我的直覺: T=GamingComputer
。 keyExtractor
comparing()
接受keyExtractor
,其類型為Function<Computer super GamingComputer, Property>
。 最后, Comparator<GamingComputer>
comparing()
返回Comparator<GamingComputer>
。
這段代碼證明了我的直覺,可以完美編譯:
Function<Computer, Property> f1 = Computer::getProperty;
Comparator<GamingComputer> c1 = comparing(f1);
現在,通過 PECS,由於c1
、 c2
被添加到集合/構造函數/方法中,只要集合處理其父類,它就可以處理任何子類。 這就是<? super T>
<? super T>
。
如此代碼所示:
Function<Computer, Property> f2 = Computer::getProperty;
Comparator<GamingComputer> c2 = comparingT(f2); // FAILS to compile. Required Type: Comparator<GamingComputer>, Provided Comparator<Computer>
Comparator<Computer> c2 = comparingT(f2); // compiles successfuly
由於f2
適用於所有Computer
,它也應該能夠與任何GamingComputer
一起使用。 但是,因為我們沒有將類型聲明為<? super T>
<? super T>
我們不能構建一個Comparator
的GamingComputers
。
說得通。 然后...
Comparator<GamingComputer> c22 = comparingT(Computer::getProperty); // compiles successfuly... WT, excuse mi French, heck???
我的猜測: comparingT()
T=GamingComputer
comparingT()
與類型T=GamingComputer
comparingT()
T=GamingComputer
強制對keyExtractor
進行向下轉換,即Computer::getProperty
。 它強制所有Computers
使用GamingComputer::getProperty
,這可能不是問題,因為Comparator<GamingComputer>
確實比較GamingComputers
。
但是,為什么這不能編譯?
Function<Computer, Property> f22 = GamingComputer::getProperty;
該錯誤非常奇特:
不能從靜態上下文中引用非靜態方法,這可能是 Intellij 的錯誤
盡管如此,在編譯時:
java: incompatible types: invalid method reference
method getPart in class function.GamingComputer cannot be applied to given types
required: no arguments
found: function.Computer
reason: actual and formal argument lists differ in length
我的直覺:
T=GamingComputer
你的直覺是正確的。
為什么
Comparator<GamingComputer> c22 = comparingT(Computer::getProperty);
編譯?
這是因為與不變的函數接口實例不同,方法引用是協變和逆變的。 使用此處的示例,您可以執行以下操作:
// in SomeClass
public static Integer function(Object o) {
return 2;
}
// ...
Function<String, Object> function = SomeCLass::function;
或者使用您的課程,您可以:
Function<GamingComputer, Property> f = Computer::getProperty;
它是“好像”方法引用有? super
? super
他們的參數和? extends
? extends
返回類型! Java 語言規范的第15.13.2節詳細說明了哪些有效,哪些無效。
所以對於c22
, T
仍然是GamingComputer
。 方法引用Computer::getProperty
可以轉換為Function<GamingComputer, Property>
它是一個方法引用。
這不會編譯,即使f2
“存儲” Computer::getProperty
:
Comparator<GamingComputer> c2 = comparingT(f2);
因為f2
本身不是方法引用。 它是一個變量。
為什么
Function<Computer, Property> f22 = GamingComputer::getProperty;
不編譯?
f22
將能夠接受任何類型的Computer
,因為它接受Computer
。 如果你給f22
另一種計算機(不是GamingComputer
), GamingComputer.getProperty
肯定無法處理,是嗎?
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.