如何在Java中正确创建对方法引用的弱引用

Seb*_*n S 2 java lambda javafx weak-references

我想一个JavaFX注册ListChangeListener一个ObservableList.但是我注意到,在某些情况下,监听器没有被调用.

(1)如果监听器是方法参考,一切都有效:

// using a direct method reference:
private final ListChangeListener<String> listener = this::listDidChange;

/* ... */
public void init() {
    list.addListener(listener);
}
Run Code Online (Sandbox Code Playgroud)

(2)但是如果Listener是同一方法的弱引用,则不调用监听器:

// using a weak method reference:
private final ListChangeListener<String> listener = new WeakListChangeListener<String>(this::listDidChange);

/* ... */
public void init() {
    list.addListener(listener);
}
Run Code Online (Sandbox Code Playgroud)

(3)现在真正有趣的部分是,它再次起作用,即使它应该与前面的例子相同:

// direct method reference wrapped into a weak ref later:
private final ListChangeListener<String> listener = this::listDidChange;

/* ... */
public void init() {
    list.addListener(new WeakListChangeListener<String>(listener));
}
Run Code Online (Sandbox Code Playgroud)

两个问题:

  • 当创建方法ref的弱引用时,究竟会发生什么?
  • (2)和(3)有什么区别?

biz*_*lop 8

创建方法引用(在本例中)就像创建任何其他对象一样.因此,如果我们用new表达式替换它,示例2变为:

private final ListChangeListener<String> listener = new WeakListChangeListener<String>(new Foo());

public void init() {
    list.addListener(listener);
}
Run Code Online (Sandbox Code Playgroud)

而示例3将是:

// direct method reference wrapped into a weak ref later:
private final ListChangeListener<String> listener = new Foo();

public void init() {
    list.addListener(new WeakListChangeListener<String>(listener));
}
Run Code Online (Sandbox Code Playgroud)

现在差异变得相当明显:

  1. 在示例2中,新创建的实例Foo立即有资格进行垃圾收集,因为没有任何强大的引用.
  2. 在示例3中Foo,您对listener字段中新创建的对象保持强引用,因此仅在收集具有listener字段的对象时才会收集它.

Ps:如果Java中的方法引用确实是对方法的引用,意味着方法本身就是第一类对象(比如在Javascript中),那么示例2也会起作用,因为每个对象都会隐式地保存对所有方法的引用.