在 java 中传递和执行成员函数

passing and enforcing a member function in java

我正在尝试创建一个工作队列 class (FooQueue),其中包含:

代码在 do 函数为静态时编译,但在函数为非静态时不编译,即使根据 this 实例函数成员的定义是正确的。

应该更改什么才能使其成为 compile/run?

public class App {
    public static void main( String[] args ) {
        FooQueue q = new FooQueue();
        q.add( FooQueue::dos, new FooItem() );    // this compiles
        q.add( q::do1, new FooItem() );           // this does not:
                                                  // does not consider q::do1 'delegate'
                                                  // as taking 2 parameters,
                                                  // with q being the first one
        FooQueue q2 = new FooQueue2();
        q.add( FooQueue2::dos, new FooItem() );   // want this to give compiler error
        q.add( FooQueue2::do1, new FooItem() );   // want this to give compiler error
    }
}

public class FooQueue {
    public static void dos( FooQueue q, FooItem item ) {
        System.out.println( "FooQueue:sdo" );
    }
    public void do1( FooItem item ) {
        System.out.println( "FooQueue:do1" );
    }
    public void add( java.util.function.BiConsumer<FooQueue,FooItem> func, FooItem wi ) {
        System.out.println( "FooQueue:addWorkItem2" );
        func.accept( this, wi );
    }
}
public class FooItem {
}
public class FooQueue2 {
    public static void dos( FooQueue2 q2, FooItem item ) {
        System.out.println( "FooQueue2:sdo" );
    }
    public void do1( FooItem item ) {
        System.out.println( "FooQueue2:do1" );
    }
}

它与静态/非静态方法无关,也与泛型无关,仅与 BiConsumer 定义有关。

BiConsumer 需要两个参数,因此您需要需要两个参数并且 return 不需要任何参数的 lambda。

要解决这个问题,请使用 实例方法参考:

FooQueue q = new FooQueue();
q.add(FooQueue::do1, new FooItem());

不要将它与静态方法引用混淆。 FooQueue::do1 是 lambda 的语法糖:

(qInstance, item) -> qInstance.do1(item));

这种方法只允许您接受来自 FooQueue 的方法。

请注意,q:do1BiConsumer 不兼容,因为它已转换为:

(item) -> q.do1(item)

阅读更多关于 Instance method reference


具有不同 类

的完整示例
public class App {
    public static void main(String[] args) {
        FooQueue q = new FooQueue();
        FooQueue2 q2 = new FooQueue2();

        q.add(FooQueue::do1, new FooItem());
        // Equals to:
        q.add((qInstance, item) -> qInstance.do1(item), new FooItem());

        // q.add(FooQueue2::do1, new FooItem());  // not compile
    }
}

class FooQueue {
    void do1(FooItem item) {
        System.out.println("FooQueue:do1");
    }

    void add(BiConsumer<FooQueue, FooItem> func, FooItem wi) {
        System.out.println("FooQueue:addWorkItem");
        func.accept(this, wi);
    }
}

// class that pretends to be FooQueue
class FooQueue2 {
    void do1(FooItem item) {
        System.out.println("FooQueue2:do1");
    }
}

class FooItem {
}