Java 多集输入和泛型的比较器

Java 多集输入和泛型的比较器,java,generics,type-inference,Java,Generics,Type Inference,我需要一个比较一番石榴多集。项目,排序计数第一和字符串第二。然而,我遇到了编译器问题,并且我认为泛型有问题 这包括: Comparator<Multiset.Entry<String>> comparator() { return Comparator.comparing(Multiset.Entry::getCount); } 比较器比较器(){ 返回Comparator.comparing(Multiset.Entry::getCount); } 然而,这

我需要一个比较一番石榴多集。项目,排序计数第一和字符串第二。然而,我遇到了编译器问题,并且我认为泛型有问题

这包括:

Comparator<Multiset.Entry<String>> comparator() {
    return Comparator.comparing(Multiset.Entry::getCount);
}
比较器比较器(){ 返回Comparator.comparing(Multiset.Entry::getCount); } 然而,这并不是:

Comparator<Multiset.Entry<String>> comparator() {
    return Comparator.comparing(Multiset.Entry::getCount).thenComparing(Multiset.Entry::getElement);
}
比较器比较器(){ 返回Comparator.comparing(Multiset.Entry::getCount),然后返回Comparator.comparing(Multiset.Entry::getElement); } 错误:java:不兼容的类型:无法推断类型变量T,U (参数不匹配;方法引用无效。) 接口com.google.common.collect.Multiset.Entry中的方法getCount无法应用于给定类型 必需:无参数 找到:java.lang.Object 原因:实际参数列表和正式参数列表长度不同) 如果我组合比较器,例如字符串,我显然没有类似的问题

Comparator<String> comparator2() {
    return Comparator.comparing(String::length).thenComparing(String::toString);
}
比较器比较器2(){ 返回Comparator.comparing(字符串::长度),然后返回Comparating(字符串::toString); } 我在这里遗漏了什么,我如何才能让它发挥作用

(注意:我知道Guava可能有不同的方法,但我想了解我在这里遇到的问题。)

我认为这是因为类型定位(Java推断的一种形式)是如何与代码中使用的点功能编程一起工作的(您可以阅读java文档中的目标类型,特别是名为:
目标类型和方法参数
的部分)

简而言之,如果我有这样的东西:

List<String> list = new List<>();
List List=新列表();
这里的目标类型是
List
,因此Java(8)意识到您正在创建的新列表被分配给并且应该是
List
类型,因此可以推断该类型,并且您不必指定类型参数

对于第一个编译的snippest来说,它归结为:代码
Comparator.comparating(Multiset.Entry::getCount);
返回一种类型的
Comparator
,该结果立即分配给方法的返回类型(即,该方法的返回类型是目标类型)。编译器可以推断类型,因为目标类型是方法
比较器
的返回类型,您在方法签名中将该方法显式定义/捕获为
比较器
。因此可以推断
比较器
中的
T

在第二段代码(不编译并且需要显式类型见证参数-方法调用中的显式位)中,您使用的是链接方法的点运算符。这意味着第二部分
thenComparing(Multiset.Entry::getElement)
应用于第一部分的Comparator.comparing结果(Multiset.Entry::getCount)

第二部分可以从目标类型推断类型,因为第二部分的结果是方法返回的结果,所以第二部分的目标类型类似于上面编译的情况-方法返回类型被捕获并定义,因此可以推断


但是对于第一部分,目标类型是不确定的,因为它没有被分配给具有实际类型的某些类型。根据Comparator API,
Comparator
是该函数返回的内容,但是因为它不知道具体将被分配给什么类型,所以需要提供类型见证并显式spe假设当它返回
Comparator
时,
T
应该是(在您的情况下)
Multiset.Entry

我并不理解为什么需要它,但是您可以通过为第一个方法调用添加显式类型参数来编译这些
然后比较
链。
Comparator.comparating(Multiset.Entry::getCount)。然后比较(Multiset.Entry::getElement);
您还应该在第一次比较中使用comparingit():
返回Comparator.comparingit(Multiset.Entry::getCount)。然后比较(Multiset.Entry::getElement);
comparingit()有道理,但它仍然需要一个显式类型参数。为什么对MultiSet.Entry有必要,而对String没有必要?可能是因为一个是泛型的,而另一个不是。我对编译器推理的了解不够,无法提前知道它什么时候可以推断,什么时候不能推断。我只是在看到它不能推断时添加类型参数。P.s。我知道的不多关于番石榴-所以不确定番石榴是否对推理工作有影响。啊,我显然没有意识到类型推理与lambdas结合的所有含义。谢谢你的详细回答,我确信它与番石榴没有特别的关系。鉴于“实际和正式的参数列表长度不同”的信息,这不可能是正确的。至少,我不明白错误大小的参数列表从何而来。@maaartinus据我所知:此方法引用不足以进行类型推断,并且由于没有目标类型(在答案中解释),因此无法推断类型。请阅读[此处]()方法引用
ObjectType::instanceMethod
转换为
函数,但这里的ObjectType是
Multiset.Entry
,它是原始类型,没有对象,被作为对象传递,因此被误认为是函数的参数类型。目标类型有助于推断对象类型
Multiset.Entry'避免这种情况。但由于点,first零件没有用于推断零件的目标类型..此处讨论Lambda表达式和方法引用。问题代码中的方法引用是“特定类型对象的实例方法引用”,即特定类的非静态方法。调用该方法时会传递该类的实例,但无法正确推断的泛型类会导致问题。
List<String> list = new List<>();