首页 > 解决方案 > 使用双冒号运算符在Java中引用任意对象的实例方法

问题描述

class Point {
    int x;
    int y;
    Point(int x, int y) {
        this.x = x;
        this.y = y;
    }
    
    public String toString() {
        return "Point(" + x + ", " + y + ")";
    }
    
    boolean filter() {
        return this.x == this.y;
    }
    
}
 
public class Test {
    public static void main(String[] args) {
        List<Point> list = new ArrayList<>();
        list.add(new Point(0, 0));
        list.add(new Point(1, 2));
        list.add(new Point(-1, -1));
        Supplier<Boolean> s = Point::filter; // Compilation Error (line n1)
        list.stream().filter(Point::filter).forEach(System.out::println); //No Error (line n2)
    }
}

在第 n2 行,如果我使用类名访问实例方法,则隐式创建一个访问的任意对象,但在第 n1 行,我得到编译错误。在哪些场景下会创建任意隐式对象?

如果我使用对象,我不会收到错误

new Point(0,0)::filter

标签: javajava-8java-stream

解决方案


在哪些场景下会创建任意隐式对象?

这两种情况下,都不会创建新对象。

Supplier<Boolean> s = Point::filter;不能编译,因为 aSupplier<Boolean>代表一个函数,它可以在你Boolean 不给它任何输入的情况下给你 a ,即我应该能够做到:

Boolean b = s.get(); // note that I am not giving "get" any input
// but s refers to the filter method in Point, which is an instance method
// I don't have any Point object in my code, yet somehow I still got a Boolean,
//  so clearly this doesn't make sense

如您所见,Point::filter不是这样的功能。要调用它,我需要先给它一个Point对象,然后它会给我一个boolean. Predicate<Point>是一个可以表示这种功能的函数式接口,所以我可以这样做:

Predicate<Point> pred = Point::filter;
boolean b = pred.test(new Point(0, 0)); // here I am giving red the instance of Point on which filter should be called

请注意,您没有filter在方法引用 ( ) 中指定应该调用哪个对象Point::filter,而是由调用者 ( pred.test(...)) 指定。这就是为什么Point::filter称为“对任意对象的实例方法的引用”。

最后,Stream.filter可以接受您的Point::filter方法的原因是因为它实际上需要 aPredicate<Point>,而不是 aSupplier<Boolean>作为参数!

当您调用时forEachPoint::filter在每个流元素上调用。具体如何做到这一点取决于流管道的实现细节。


推荐阅读