我最近把手放在Java 8上并尝试使用方法参考。 我正在尝试不同类型的方法引用并陷入类型"引用特定类型的任意对象的实例方法"。
String[] arr = {"First", "Second", "Third", "Fourth"};
Arrays.sort(arr, String::compareToIgnoreCase);
这非常有效。但是当我尝试通过其类型引用用户定义类的方法时:
Demo2[] arr = {a, b};
Arrays.sort(arr, Demo2::compare);
这显示编译时错误为"无法从静态上下文引用非静态方法"。
这是Demo2课程:
public class Demo2 implements Comparator<Demo2> {
Integer i;
Demo2(Integer i1){
i = i1;
}
public Integer getI() {
return i;
}
@Override
public int compare(Demo2 o1, Demo2 o2) {
return o1.getI().compareTo(o2.getI());
}
}
答案 0 :(得分:5)
正如greg-449指出的那样,你的代码有一个错误。
通过制作类似YourObjet::yourMethod
的方法引用,您可以对实例的方法进行静态引用。因此,将为每个对象调用该方法,因此签名需要与早期的
将编译的代码将具有以下形式:
Demo2[] demos = {a, b};
Arrays.sort(demos, Demo2::compareTo);
public class Demo2 {
Integer i;
Demo2(Integer i1){
i = i1;
}
public Integer getI() {
return i;
}
public int compareTo(Demo2 other) {
return this.getI().compareTo(other.getI());
}
}
但正如RealSkeptic指出的那样,这不是实施和对象比较的正确方法。你应该给Arrays.sort方法一个比较器:
Arrays.sort(demos, (obj1, obj2) -> obj1.getI().compareTo(obj2.getI()));
答案 1 :(得分:3)
Comparator
所需的Arrays.sort(T[],Comparator<T>)
接口有一个接受两个相同类型T
的对象引用的方法,并返回一个整数。
方法引用中有一些“魔力”。 Java所做的是以适合接口要求的方式包装方法。
接口当然不需要静态方法。但是包装可以创建调用静态方法的方法,如Tutorial的第一个示例所示:
public static int compareByAge(Person a, Person b) {
return a.birthday.compareTo(b.birthday);
}
它以一种类似于
的方式包装它new Comparator<Person>() {
@Override
public int compare(Person a, Person b) {
return Person.compareByAge(a,b);
}
}
满足界面。
但是在“引用特定类型的任意对象的实例方法”一节中的示例中,它以不同的方式包装它。它需要一个接收两个字符串的方法,但它有一个只接收一个字符串的方法。这就是String::compareToIgnoreCase
的定义方式:
public int compareToIgnoreCase(String str)
但在这种情况下,它是一个实例方法。 Java现在做的是什么,因为这个方法属于String
类型的对象,并且接受类型为String
的对象,很容易在它周围构建一个“包裹”,使其成为一个方法,接受两个对象,就像lambda表达式一样:
(String a, String b) -> {
return a.compareToIgnoreCase( b );
}
或者,如果我们想象一个正式的包装为Comparator
:
new Comparator<String>() {
@Override
public int compare(String a, String b) {
return a.compareToIgnoreCase(b);
}
}
因此,它是属于类型T
的实例方法,接受类型T
并返回int
这一事实允许Java适当地包装它以使其适合{{1} } interface。
但是Comparator
不符合这种模式。它接受两个参数。如果一个方法接受两个参数,它必须是一个静态方法来适应包装规则 - 没有办法将“this”对象传递给int compare(Demo2 o1, Demo2 o2)
接口。因此它尝试将其包装为静态方法,并且失败,因为它不是静态方法。
结论:你得到了错误,因为对于这种特殊类型的方法引用,你需要一个只有一个参数的实例方法,该参数与类相同。
正如@Holger在评论中提到的那样,如果您正在构建一个新类,则不应该在其中专门为此类排序任务添加比较方法。如果该类具有自然顺序,请将其设为Comparator
并使用Comparable
。如果没有,并且您需要根据其任何属性对其进行排序,请使用lambda表达式或Arrays.sort(Object[])
,以便更好地利用现有的getter来进行比较。
答案 2 :(得分:1)
作为惯例,Comparator<T>
使用 lambda表达式实现,在类中实现它看起来很奇怪。
Demo2[] array = new Demo2[2];
array[0] = new Demo2(12);
array[1] = new Demo2(32);
Comparator<Demo2> demo2Comparator = (e1,e2)->e1.getI().compareTo(e2.getI());
Arrays.sort(array, demo2Comparator);