Java 8 为什么更改侦听器的行为<;T>;根据T参数的不同而不同

Java 8 为什么更改侦听器的行为<;T>;根据T参数的不同而不同,java-8,javafx-8,Java 8,Javafx 8,考虑以下计划: import javafx.beans.property.ListProperty; import javafx.beans.property.SimpleListProperty; import javafx.beans.property.SimpleStringProperty; import javafx.beans.property.StringProperty; import javafx.collections.FXCollections; /** * * @a

考虑以下计划:

import javafx.beans.property.ListProperty;
import javafx.beans.property.SimpleListProperty;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import javafx.collections.FXCollections;

/**
 *
 * @author kachna
 */
public class ListPropertyTest {

    public static void main(String[] args) {
        StringProperty p = new SimpleStringProperty();
        p.addListener((obs, old, nw) -> {
            System.out.println("String Property; oldString: " + old + ", newString: " + nw);
        });
        p.set("1");

        ListProperty<String> listProperty = new SimpleListProperty<>(FXCollections.observableArrayList());
        listProperty.addListener((obs, old, nw) -> {
            System.out.println("ListProperty; oldList:  " + old + ", newList: " + nw);

        });

        listProperty.addAll("1", "2", "3");

    }
}
如您所见,旧值为:

  • null
    T
    字符串时
  • T
    可观察列表

  • 这是一个错误:
    ListProperty
    当包装列表的内容更改时,不应该触发更改的事件:它应该只触发列表更改的事件。换句话说,您应该只能检测来自的更改

    listProperty.addAll("1", "2", "3");
    
    与听众

    listProperty.addListener((ListChangeListener<? extends String> change) -> {
        // e.g.
        while (change.next()) {
            if (change.wasAdded()) {
                System.out.println(change.getAddedSubList());
            }
        }
    });
    
    这可能是一个在不破坏大量现有代码的情况下无法修复的错误:我不知道是否有计划纠正这个错误


    实际发生的是,正在触发更改事件,但旧值和新值引用同一个列表(因为实际的包装列表引用没有更改)。因此,当然,
    toString()
    方法返回相同的值,无论您是从
    old
    还是
    nw
    调用它,并给出列表的当前内容。

    看起来像是可变数据的一般问题。更改列表实例的内容时,列表实例是相同的,因此旧值和新值都是对同一列表的引用,但由于通知是在修改后发生的,因此无论您使用哪个引用来访问列表,列表都会显示新内容,当然。我调试了它,看起来它来自
    com.sun.javafx.binding.ListExpressionHelper.fireValueChangedEvent(change)
    。这种方法使旧值和新值相同。我认为你的推理是正确的。但是我已经阅读了以下内容(来自Learn Javafx8电子书):
    当列表的内容发生变化时,ChangeListeners的changed()方法接收到对与新旧值相同的列表的引用。如果ObservableList的包装引用被替换为新的引用,此方法将接收旧列表和新列表的引用。
    是的,好的,这与我所说的基本相同。但是,我认为不应该在第一种情况下触发该事件,因为包装的引用没有更改。
    listProperty.addListener((ListChangeListener<? extends String> change) -> {
        // e.g.
        while (change.next()) {
            if (change.wasAdded()) {
                System.out.println(change.getAddedSubList());
            }
        }
    });
    
    listProperty.setValue(FXCollections.observableArrayList("1","2","3"));