2015-06-26 6 views
2

Я хочу зарегистрировать JavaFX ListChangeListener на ObservableList. Однако я заметил, что при определенных обстоятельствах слушателя не звонят.Как правильно создать слабую ссылку на ссылку на метод в Java

(1) Если прослушиватель эталонный метод, все работает:

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

/* ... */ 
public void init() { 
    list.addListener(listener); 
} 

(2) Однако, если прослушиватель слабый реф к тому же методу, что слушатель не вызывается :

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

/* ... */ 
public void init() { 
    list.addListener(listener); 
} 

(3) Теперь действительно забавное в том, что это снова работает, даже если она должна быть такой же, как Previou s пример:

// 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)); 
} 

Два вопроса:

  • Что именно происходит, когда слабая ссылку на метод исй создаются?
  • В чем разница между (2) и (3)?
+5

В соответствии с JavaDoc для WeakListChangeListener: «Примечание. Необходимо сохранить ссылку на ListChangeListener, которая была передана до тех пор, пока она используется, иначе в скором времени будет собран мусор». – neuronaut

ответ

8

Создание ссылки на метод (в данном случае) подобно созданию любого другого объекта. Так что, если мы заменим его с выражением new, пример 2 становится как:

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

public void init() { 
    list.addListener(listener); 
} 

В то время как пример 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)); 
} 

Теперь разница становится достаточно очевидным:

  1. В примере 2 вновь созданный экземпляр Foo мгновенно имеет право на сбор мусора, поскольку ничто не содержит ссылки на него.
  2. В примере 3 вы сохраняете сильную ссылку на только что созданный объект Foo в поле listener, поэтому он будет собран только тогда, когда будет собрано объект с полем listener.

Ps: Если ссылки метод в Java действительно были ссылки на методы, а это означает, что методы были объектами первого класса в своем собственном праве (как в JavaScript), пример 2 будет работать также, поскольку каждый объект будет неявно держать ссылка на все их методы.