方法引用似乎并不总是捕获实例

时间:2019-06-05 10:39:47

标签: java java-8 instance functional-interface supplier

我知道即使是very recent one上也有很多问题,但是我仍然无法解决一件事。考虑以下功能界面

@FunctionalInterface
interface PersonInterface {
    String getName();
}

此实现:

class Person implements PersonInterface {
    private String name;

    public Person(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

如果我查看这些线程12,我希望以下代码能够输出"Bob"而不会抛出NullPointerException,因为据我所知,当我创建了我的供应商,它捕获了Person实例。

Person p = new Person("Bob");
Supplier<String> f = p::getName;
p = null;
System.out.println(f.get());

它正确输出"Bob"

现在我不明白的是为什么下面的代码也不能输出"Bob"

Person p = new Person("Bob");
Supplier<String> f = p::getName;
p.setName("Alice");
System.out.println(f.get());

它实际上输出"Alice"

在我看来,在第一个示例中,lambda在创建对象时捕获了Person对象的状态,并且在尝试调用它时不尝试重新评估它,而在第二种情况下,好像不会捕获它,而是在调用它时对其进行重新评估。

编辑 重新阅读其他主题并得到Eran的回答后,我用2个Persons指向同一实例来写了该位:

Person p1 = new Person("Bob");
Person p2 = p1;
Supplier<String> f1 = p1::getName;
Supplier<String> f2 = p2::getName;
p1 = null;
p2.setName("Alice");
System.out.println(f1.get());
System.out.println(f2.get());

现在我可以看到,即使p1为空,它们都输出"Alice",因此方法引用捕获了实例本身,而不是我错误地假设的状态。

2 个答案:

答案 0 :(得分:6)

  

在我看来,在第一个示例中,lambda在创建对象时捕获了Person对象的状态,并且在尝试调用它时不尝试重新评估它,而在第二种情况下,好像不会捕获它,而是在调用它时对其进行重新评估。

首先,它是方法参考,而不是lambda表达式。

在两种情况下,方法引用(不是“ Person对象的状态”)都捕获对// First convert the single channel mat to 3 channel mat Imgproc.cvtColor(foregroundMask, foregroundMask, Imgproc.COLOR_GRAY2BGR); // Now simply take min operation Mat out; Core.min(foregroundMask, image, out); 实例的引用。这意味着,如果Person实例的状态发生突变,则执行功能接口的方法的结果可能会更改。

方法引用不会创建它捕获其引用的Person实例的副本。

答案 1 :(得分:6)

这与lambda或方法引用无关,这只是您正在使用的这些构造的副作用。

出于更简单的推理,您可以将其考虑为:

static class SupplierHolder {
    private final Person p;
    // constructor/getter
}

static class Person {
    private String name;
    // constructor/getter/setter
}

创建Supplier<String> f = p::getName;时,可以将其想象为创建一个SupplierHolder,该PersongetName作为输入,并具有对其Person p = new Person("Bob"); SupplierHolder sh = new SupplierHolder(p); p = null; // this has no effect on the reference that SupplierHolder holds System.out.println(sh.getPerson().getName()); 的方法引用。 / p>

这就像在做

Person p = new Person("Bob");
SupplierHolder sh = new SupplierHolder(p); 
p.setName("Alice");

在第二个示例中,您具有:

p

现在SupplierHolder引用和from django import template from django.utils.safestring import mark_safe from markdownx.utils import markdownify register = template.Library() @register.filter def formatted_markdown(text): return mark_safe(markdownify(text)) 持有的引用在同一实例上“作用”-它们指向同一对象。

实际上,这并不完全相同,但是我想证明了这一点。