方法引用的类型是什么?
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) 兼容
我承认这个问题太复杂了,我无法不尝试就回答,但我试图理解你的问题,因此提供了我对这种情况的理解——你的方法很好。基本上你在这里做以下事情 -
- 使用 shorthand 语法实现匿名 class,实现 功能接口 - 这很好。
- 让编译器知道使用
A::method1
作为 I.m
的实现 - 这也很好。
- 因为
A::method1
已经存在,您可以使用方法引用而不是 lambda 表达式 - - 这也很好。
- 实际参数
c
的传递在行 foo
方法的主体中完成 - b=i.m(a,c)
。这里用于 c
的实际参数应该传递给 A::method1
.
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);
...
}
假设我们有
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) 兼容
- 引用returns
我承认这个问题太复杂了,我无法不尝试就回答,但我试图理解你的问题,因此提供了我对这种情况的理解——你的方法很好。基本上你在这里做以下事情 -
- 使用 shorthand 语法实现匿名 class,实现 功能接口 - 这很好。
- 让编译器知道使用
A::method1
作为I.m
的实现 - 这也很好。 - 因为
A::method1
已经存在,您可以使用方法引用而不是 lambda 表达式 - - 这也很好。 - 实际参数
c
的传递在行foo
方法的主体中完成 -b=i.m(a,c)
。这里用于c
的实际参数应该传递给A::method1
. 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);
...
}