对特定对象的实例方法的引用的概念是否会破坏Java中的类型安全性?
根据
https://docs.oracle.com/javase/tutorial/java/javaOO/methodreferences.html
你可以有一个自定义类ComparisonProvider,它不实现Comparator接口,仍然使用这个类的实例作为方法的第二个参数
Arrays.sort(T [] a,Comparator c)
当然,您的ComparisonProvider的实现必须有一个方法,其签名与Comparator.compare()方法完全匹配,但这仍然不是Comparator的实例,不是吗?
从本质上讲,Java 8允许我们使用类的实例,就像它们实现特定的接口一样,而实际上它们不是。
这意味着,我们在Java中失去了Type-safety,对吗?
答案 0 :(得分:3)
lambda表达式和方法引用没有预定义类型,它们是多义表达式,如here所示。这意味着它们的类型来源于它们的使用环境。
在您的示例中,这两者都是合法的,例如:
BiFunction<Person, Person, Integer> biFun = myComparisonProvider::compareByName;
Comparator<Person> comp = myComparisonProvider::compareByName;
但与此同时你无法做到:
Arrays.sort(pers, biFun);
当您实际尝试按如下方式对数组进行排序时:
Arrays.sort(pers, myComparisonProvider::compareByName);
在 a Comparator
:
// InvokeDynamic #0:compare:(LTest$ComparisonProvider;)Ljava/util/Comparator;
另请注意,这将打印为true:
Comparator<Person> comp = myComparisonProvider::compareByName;
System.out.println(comp instanceof Comparator); // true
您可以启用标记:-Djdk.internal.lambda.dumpProxyClasses=/Your/Path/Here
并查看该方法引用转换为:
final class Test$$Lambda$1 implements java.util.Comparator
并且在其中有compare
方法实现(我已将其简化并删除了一些代码以使其更加明显):
public int compare(java.lang.Object, java.lang.Object);
Code:
4: aload_1
5: checkcast // class Test3$Person
8: aload_2
9: checkcast // class Test$Person
12: invokevirtual Test$ComparisonProvider.compareByName:(Test$Person;Test$Person;)I
答案 1 :(得分:1)
Java 8允许我们使用类的实例,就像它们实现特定的接口一样,而实际上它们不是
不完全是,它允许您使用某个类实例的单个方法,就像它实现了一些功能接口一样。
它没有添加Java 7中不存在的任何功能 - 它只是为您提供了编写该功能的捷径。
例如,而不是:
Arrays.sort(someArray, someInstance::someMethod);
在Java 7中,您可以使用匿名类实例来编写:
Arrays.sort(someArray, new Comparator<SomeType> () {
public int compare (SomeType one, SomeTypeTwo) {
return someInstance.someMethod(one,two);
}
});
只要实例方法可访问(即公开),您就可以根据需要使用它。
答案 2 :(得分:1)
NId
是功能接口,这意味着当您请求时,您可以传递实现它的类的实例,使用符合声明的单个抽象方法类型的lambda表达式在其中或使用也符合的方法参考。
Java 8 功能界面有所不同。这试图抓住功能的概念。毕竟在Comparator
中重要的不是类型本身,而是应该在运行时提供的方法(及其类型)。在Java 8之前,您需要提供一个函数对象,而在Java 8中,您可以简单地提供函数(正是需要的函数)。
因此,对于类型系统,一切都是正确的,前提是您使用的lambdas或引用属于功能接口方法的类型。