簡體   English   中英

Java Comparator 類中的泛型。 T和U的確切類型是什么?

[英]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,由於c1c2被添加到集合/構造函數/方法中,只要集合處理其父類,它就可以處理任何子類。 這就是<? 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>我們不能構建一個ComparatorGamingComputers

說得通。 然后...

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 8 流中的靜態上下文引用非靜態方法

盡管如此,在編譯時:

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節詳細說明了哪些有效,哪些無效。

所以對於c22T仍然是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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM