Java 比较器 class 中的泛型。 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
。 comparing()
接受keyExtractor
,其类型为Function<Computer super GamingComputer, Property>
。最后,comparing()
returnsComparator<GamingComputer>
.
这段代码,证明了我的直觉,编译完美:
Function<Computer, Property> f1 = Computer::getProperty;
Comparator<GamingComputer> c1 = comparing(f1);
现在,通过 PECS,由于 c1
,c2
被添加到集合/构造函数/方法中,只要集合处理它们的 parent class ,它可以处理任何 child class。这就是 <? 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>
,所以我们无法构造GamingComputers
的Comparator
。
有道理。那么...
Comparator<GamingComputer> c22 = comparingT(Computer::getProperty); // compiles successfuly... WT, excuse mi French, heck???
我的猜测:comparingT()
类型 T=GamingComputer
强制对 keyExtractor
进行向下转换,即 Computer::getProperty
。它强制所有 Computers
使用 GamingComputer::getProperty
,这可能不是问题,因为 Comparator<GamingComputer>
确实比较 GamingComputers
.
但是,为什么这不能编译?
Function<Computer, Property> f22 = GamingComputer::getProperty;
错误很奇特:
Non-static 方法无法从静态上下文中引用,这可能是来自 Intellij
的 bug
仍然,编译时:
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
My intuition: T=GamingComputer
你的直觉是正确的。
Why does Comparator<GamingComputer> c22 = comparingT(Computer::getProperty);
compile?
这是因为与不变的功能接口实例不同,方法引用是协变和逆变的。使用 here 中的示例,您可以执行以下操作:
// in SomeClass
public static Integer function(Object o) {
return 2;
}
// ...
Function<String, Object> function = SomeCLass::function;
或者使用您的 类,您可以:
Function<GamingComputer, Property> f = Computer::getProperty;
“就好像”方法引用在它们的参数上有 ? super
并且在 return 类型上有 ? extends
! Java 语言规范的 15.13.2 部分详细说明了哪些有效,哪些无效。
所以对于 c22
,T
仍然是 GamingComputer
。方法引用 Computer::getProperty
可以转换为 Function<GamingComputer, Property>
它是一个方法引用。
这不会编译,即使 f2
“存储”Computer::getProperty
:
Comparator<GamingComputer> c2 = comparingT(f2);
因为f2
本身不是方法引用。它是一个变量。
Why does Function<Computer, Property> f22 = GamingComputer::getProperty;
not compile?
f22
可以接受任何类型的 Computer
,因为它接受 Computer
。如果给 f22
另一种计算机(不是 GamingComputer
),GamingComputer.getProperty
肯定无法处理,是吗?
考虑以下两种方法。它们唯一的区别在于它们的泛型类型声明 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
。 comparing()
接受keyExtractor
,其类型为Function<Computer super GamingComputer, Property>
。最后,comparing()
returnsComparator<GamingComputer>
.
这段代码,证明了我的直觉,编译完美:
Function<Computer, Property> f1 = Computer::getProperty;
Comparator<GamingComputer> c1 = comparing(f1);
现在,通过 PECS,由于 c1
,c2
被添加到集合/构造函数/方法中,只要集合处理它们的 parent class ,它可以处理任何 child class。这就是 <? 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>
,所以我们无法构造GamingComputers
的Comparator
。
有道理。那么...
Comparator<GamingComputer> c22 = comparingT(Computer::getProperty); // compiles successfuly... WT, excuse mi French, heck???
我的猜测:comparingT()
类型 T=GamingComputer
强制对 keyExtractor
进行向下转换,即 Computer::getProperty
。它强制所有 Computers
使用 GamingComputer::getProperty
,这可能不是问题,因为 Comparator<GamingComputer>
确实比较 GamingComputers
.
但是,为什么这不能编译?
Function<Computer, Property> f22 = GamingComputer::getProperty;
错误很奇特:
Non-static 方法无法从静态上下文中引用,这可能是来自 Intellij
的 bug仍然,编译时:
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
My intuition:
T=GamingComputer
你的直觉是正确的。
Why does
Comparator<GamingComputer> c22 = comparingT(Computer::getProperty);
compile?
这是因为与不变的功能接口实例不同,方法引用是协变和逆变的。使用 here 中的示例,您可以执行以下操作:
// in SomeClass
public static Integer function(Object o) {
return 2;
}
// ...
Function<String, Object> function = SomeCLass::function;
或者使用您的 类,您可以:
Function<GamingComputer, Property> f = Computer::getProperty;
“就好像”方法引用在它们的参数上有 ? super
并且在 return 类型上有 ? extends
! Java 语言规范的 15.13.2 部分详细说明了哪些有效,哪些无效。
所以对于 c22
,T
仍然是 GamingComputer
。方法引用 Computer::getProperty
可以转换为 Function<GamingComputer, Property>
它是一个方法引用。
这不会编译,即使 f2
“存储”Computer::getProperty
:
Comparator<GamingComputer> c2 = comparingT(f2);
因为f2
本身不是方法引用。它是一个变量。
Why does
Function<Computer, Property> f22 = GamingComputer::getProperty;
not compile?
f22
可以接受任何类型的 Computer
,因为它接受 Computer
。如果给 f22
另一种计算机(不是 GamingComputer
),GamingComputer.getProperty
肯定无法处理,是吗?