mirror of
https://github.com/LingCoder/OnJava8.git
synced 2026-08-31 03:38:07 +08:00
[ISSUE #24]校订第13章函数式编程-未绑定的方法引用
This commit is contained in:
@@ -430,12 +430,12 @@ Go::go()
|
||||
### 未绑定的方法引用
|
||||
|
||||
|
||||
未绑定的方法引用是指没有关联对象的普通(非静态)方法。 要使用未绑定的引用,你必须提供以下对象:
|
||||
未绑定的方法引用是指没有关联对象的普通(非静态)方法。 使用未绑定的引用之前,我们必须先提供对象:
|
||||
|
||||
```java
|
||||
// functional/UnboundMethodReference.java
|
||||
|
||||
// Method reference without an object
|
||||
// 没有方法引用的对象
|
||||
|
||||
class X {
|
||||
String f() { return "X::f()"; }
|
||||
@@ -455,25 +455,29 @@ public class UnboundMethodReference {
|
||||
TransformX sp = X::f;
|
||||
X x = new X();
|
||||
System.out.println(sp.transform(x)); // [2]
|
||||
System.out.println(x.f()); // Same effect
|
||||
System.out.println(x.f()); // 同等效果
|
||||
}
|
||||
}
|
||||
/* Output:
|
||||
X::f()
|
||||
X::f()
|
||||
*/
|
||||
```
|
||||
|
||||
到目前为止,我们已经看到了对与其关联接口具有相同签名的方法的引用。 在 **[1]**,我们尝试对X中的 `f()` 做同样的事情,试图分配给 **MakeString**。 这会产生编译器关于“无效方法引用”的错误 (“invalid method reference),即使 `make()` 与 `f()` 具有相同的签名。 问题是实际上还有另一个(隐藏的)参数:我们的老朋友 `this`。 你不能在没有 `X` 对象的情况下调用 `f()` 来调用它。 因此,`X :: f` 表示未绑定的方法引用,因为它尚未“绑定”到对象。
|
||||
输出结果:
|
||||
|
||||
要解决这个问题,我们需要一个 `X` 对象,所以我们的接口实际上需要一个额外的参数,就像你在 **TransformX** 中看到的那样。 如果将 `X :: f` 分配给 **TransformX**,Java 很高兴。 我们现在必须进行第二次心理调整 - 使用未绑定的引用时,函数方法的签名(接口中的单个方法)不再与方法引用的签名完全匹配。 有一个很好的理由说服你,那就是你需要一个对象来调用方法。
|
||||
```
|
||||
X::f()
|
||||
X::f()
|
||||
```
|
||||
|
||||
**[2]** 的结果有点像脑筋急转弯。 我接受未绑定的引用并对其调用 `transform()`,将其传递给X,并以某种方式导致对 `x.f()` 的调用。 Java知道它必须采用第一个参数,实际上是这个,并在其上调用方法。
|
||||
|
||||
截止目前,我们已经知道了与接口方法同名的方法引用。 在 **[1]**,我们尝试把 `X` 的 `f()` 方法引用赋值给 **MakeString**。结果:即使 `make()` 与 `f()` 具有相同的签名,编译也会报“invalid method reference”(无效方法引用)错误。 这是因为实际上还有另一个隐藏的参数:我们的老朋友 `this`。 你不能在没有 `X` 对象的前提下调用 `f()`。 因此,`X :: f` 表示未绑定的方法引用,因为它尚未“绑定”到对象。
|
||||
|
||||
要解决这个问题,我们需要一个 `X` 对象,所以我们的接口实际上需要一个额外的参数的接口,如上例中的 **TransformX**。 如果将 `X :: f` 赋值给 **TransformX**,这在 Java 中是允许的。这次我们需要调整下心里预期——使用未绑定的引用时,函数方法的签名(接口中的单个方法)不再与方法引用的签名完全匹配。 理由是:你需要一个对象来调用方法。
|
||||
|
||||
**[2]** 的结果有点像脑筋急转弯。 我接受未绑定的引用并对其调用 `transform()`,将其传递给 `X`,并以某种方式导致对 `x.f()` 的调用。 Java 知道它必须采用第一个参数,这实际上就是 `this`,并在其上调用方法。
|
||||
|
||||
```java
|
||||
// functional/MultiUnbound.java
|
||||
|
||||
// Unbound methods with multiple arguments
|
||||
// 未绑定的方法与多参数的结合运用
|
||||
|
||||
class This {
|
||||
void two(int i, double d) {}
|
||||
@@ -549,11 +553,11 @@ public class CtorReference {
|
||||
}
|
||||
```
|
||||
|
||||
**Dog** 有三个构造函数,函数接口内的 `make()` 方法反映了构造函数参数列表( make()方法可以有不同的名称)。
|
||||
**Dog** 有三个构造函数,函数接口内的 `make()` 方法反映了构造函数参数列表( `make()` 方法名称可以不同)。
|
||||
|
||||
注意我们如何对 **[1]**,**[2]** 和 **[3]** 中的每一个使用 `Dog :: new`。 所有三个构造函数只有一个名称:`:: new`。 但是构造函数引用在每种情况下都分配给不同的接口,并且编译器可以知道从哪个构造函数引用中进行检测。
|
||||
**注意**我们如何对 **[1]**,**[2]** 和 **[3]** 中的每一个使用 `Dog :: new`。 这 3 个构造函数只有一个相同名称:`:: new`,但在每种情况下都分配给不同的接口。编译器可以检测并知道从哪个构造函数引用。
|
||||
|
||||
编译器可以看到调用函数方法( 在本例中为 `make()`)意味着调用构造函数。
|
||||
编译器能识别并调用你的构造函数( 在本例中为 `make()`)。
|
||||
|
||||
<!-- Functional Interfaces -->
|
||||
## 函数式接口
|
||||
|
||||
Reference in New Issue
Block a user