方法引用的类型是什么?

What's the type of a method reference?

假设我们有

class A {
   B method1 (C c) { ... }
}

作为方法参考的 method1 的类型是什么?

这是,foo() 的调用的方法签名是什么?:

foo (A::method1);

注:

我定义了一个接口

interface I {
   B m (A a, C c);
}

似乎将 foo 声明为

是正确的
void foo (I i) { }

(因为它匹配调用 foo(A::method1) --在 foo 里面你必须写 b=i.m(a,c) 来表示 b=a.method1(c)).

这是唯一的出路吗?

方法引用和 lambda 是目标类型的以匹配 SAM interfaces。在您的情况下,它必须匹配 I,因为那是 foo 参数的类型。

通俗解释:

请记住,方法引用可以被认为是某些 lambda 的替代语法,并且 lambda 都实现了一个或多个 functional interfaces

请记住,lambda 表达式(目前)是一种以更简洁的形式编写一些 single-method 匿名 classes 的方法;因此,lambda 总是可以简化为匿名的 class(但并非总是相反)。

所以

foo (A::method1);

可以变成

foo ((c) -> <body>);

可以简化为匿名class:

foo (new Function<B>() {
    <body>
});

这是一个匿名的 class,它是 Function

的子类型

方法引用因此是它们所代表的任何功能接口的匿名子类型,因此参数的类型必须是相应的功能接口或其超类型之一。


JLS 实际上有一个标题为“15.13.2. 方法引用的类型”的部分,但措辞可能有点晦涩。简而言之:

方法引用可以用作类型 T 如果:

  • T 是功能接口类型(第 9.8 节)
  • 功能接口的抽象方法与方法引用的compile-time类型匹配
  • 或者:
    • 引用returns void
    • 引用return是一个可以分配给相应功能接口类型的类型,例如方法引用必须 return Number 或子类型才能与 B foo(Function f)
    • 兼容

我承认这个问题太复杂了,我无法不尝试就回答,但我试图理解你的问题,因此提供了我对这种情况的理解——你的方法很好。基本上你在这里做以下事情 -

  1. 使用 shorthand 语法实现匿名 class,实现 功能接口 - 这很好。
  2. 让编译器知道使用 A::method1 作为 I.m 的实现 - 这也很好。
  3. 因为 A::method1 已经存在,您可以使用方法引用而不是 lambda 表达式 - - 这也很好。
  4. 实际参数 c 的传递在行 foo 方法的主体中完成 - b=i.m(a,c)。这里用于 c 的实际参数应该传递给 A::method1.
  5. a.method1 中的对象 a 仍然是 任意 根据 java 8 规范,因为您指定 Class::Method 和不是 Instance::Method

您可以使用现有的 BiFunction:

而不是声明新接口
void foo(BiFunction<? super A, ? super C, ? extends B> fn) {
    ...
    B b = fn.apply(a, c);
    ...
}