2

说我们有

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) --insidefoo你必须写成b=i.m(a,c)mean b=a.method1(c))。

这是唯一的出路吗?

4

4 回答 4

3

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

于 2015-09-28T22:11:00.237 回答
1

非正式解释:

请记住,可以将方法引用视为某些 lambda 的替代语法,并且 lambda 都实现了一个或多个功能接口

请记住,lambdas(目前)是一种以更简洁的形式编写一些单方法匿名类的方法;因此,lambdas 总是可以简化为匿名类(但并非总是相反)。

所以

foo (A::method1);

可以变成

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

可以简化为匿名类:

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

这是一个匿名类,是 Function 的子类型

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


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

在以下情况下,方法引用可以用作类型T

  • T是一种功能接口类型(第 9.8 节)
  • 功能接口的抽象方法与方法引用的编译时类型相匹配
  • 任何一个:
    • 参考返回void
    • 引用返回一个类型,该类型可以分配给功能接口的相应类型,例如必须返回一个方法引用Number或一个子类型以兼容 `B foo(Function f)
于 2015-09-28T22:13:27.087 回答
1

您可以使用现有的,而不是声明新接口BiFunction

void foo(BiFunction<? super A, ? super C, ? extends B> fn) {
    ...
    B b = fn.apply(a, c);
    ...
}
于 2015-09-29T02:20:40.040 回答
0

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

  1. 使用简写语法来拥有一个实现功能接口的匿名类- 这很好。
  2. 让编译器知道将其A::method1用作 - 的实现,I.m 这也很好。
  3. 因为A::method1已经存在,您可以使用方法引用而不是 lambda 表达式 - 这也很好。
  4. 实际参数的传递是在- 行的方法c体中完成的。此处使用的实际参数应该传递给.foob=i.m(a,c)cA::method1
  5. 根据您指定的此语法的 Java 8 规范,对象aina.method1仍然是任意Class::Method的,而不是Instance::Method
于 2015-09-28T22:45:34.967 回答