java - Java Comparator 类中的泛型。T 和 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 }
, where GamingComputer
extends Computer
。现在,我想对它们进行排序。
List.sort( comparing( Computer::getProperty ) )
T的类型是什么?
我的直觉:T=GamingComputer
。comparing()
接受keyExtractor
,其类型为Function<Computer super GamingComputer, Property>
。最后,comparing()
返回Comparator<GamingComputer>
。
这段代码证明了我的直觉,可以完美编译:
Function<Computer, Property> f1 = Computer::getProperty;
Comparator<GamingComputer> c1 = comparing(f1);
现在,由于 PECS被添加到集合/构造函数/方法中c1
,c2
只要集合处理它们的父类,它就可以处理任何子类。这就是背后的原因<? 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
适用于 all Computer
,因此它也应该能够适用于 any GamingComputer
。但是,因为我们没有将 type 声明为<? super T>
,所以我们无法构造 a Comparator
of GamingComputers
。
说得通。然后...
Comparator<GamingComputer> c22 = comparingT(Computer::getProperty); // compiles successfuly... WT, excuse mi French, heck???
我的猜测:comparingT()
with typeT=GamingComputer
强制keyExtractor
对Computer::getProperty
. 它强制所有人Computers
使用GamingComputer::getProperty
,这可能不是问题,因为Comparator<GamingComputer>
确实 compare 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
在它们的参数和? extends
返回类型上!Java 语言规范的第15.13.2节详细说明了哪些有效,哪些无效。
所以对于c22
,T
依然GamingComputer
。方法引用Computer::getProperty
可以转换为Function<GamingComputer, Property>
它的方法引用。
这不会编译,即使f2
"stores" Computer::getProperty
:
Comparator<GamingComputer> c2 = comparingT(f2);
因为f2
它本身不是方法引用。它是一个变量。
为什么不
Function<Computer, Property> f22 = GamingComputer::getProperty;
编译?
f22
将能够接受任何一种Computer
,因为它接受Computer
。如果你给f22
另一种电脑(不是GamingComputer
),GamingComputer.getProperty
肯定不能处理,不是吗?
推荐阅读
- bamboo - 竹脚本构建计划
- apache-spark - Spark - 如何针对 RDD 中的大量列优化 Row 对象
- javascript - 为什么此 mouseenter 事件不适用于标签内的标签
- php - 查找字符串中任何大于某个数字的数字第一次出现的位置
- pandas - 使用熊猫有条件地更新多索引框架
- javascript - 无法在简单的 jQuery 循环中获取未定义或空引用的属性“nodeValue”
- javascript - 单选按钮 Checked 属性在 JsViews 中不起作用
- javascript - 在 Vue.js 中保持组件存活
- java - 使用 Subject.doAs 运行 EJB 不会影响 Wildfly 15 中的 EJBContext
- installation - 在 Windows 2008 Server 上更新 IBM Websphere 8.5.5.14 和 Java 1.7