为什么可观察列表不总是注意到变化?

时间:2019-05-29 03:14:47

标签: java javafx listener observers

我有一些我不明白结果的代码:

ObservableList<Integer> li = FXCollections.observableArrayList();
        li.add(1);
        li.add(2);
        IntegerProperty intProp = new SimpleIntegerProperty(5);

        li.add(intProp.getValue());

        li.add(li.get(0) + li.get(2));
        System.out.println(li);
        li.addListener((ListChangeListener<Integer>) change -> {
            li.set(3, li.get(0) + li.get(2));
        });
        intProp.setValue(3);
        System.out.println(intProp.get());
        System.out.println(li.get(2));
        System.out.println(li);

我不明白为什么更改intProp的值不会影响observableList,我的意思是位置2中的int应该是属性的值,因此第二个和第三个sysout必须相同,并且首先必须与最后一个不同,但这不是事实,它给了我:

[1, 2, 5, 6]
3
5
[1, 2, 5, 6]

我尝试通过编写以下代码进行一些更改:

        ObservableList<Integer> li = FXCollections.observableArrayList();
        li.add(1);
        li.add(2);

        li.add(5);

        li.add(li.get(0) + li.get(2));
        System.out.println(li);
        li.addListener((ListChangeListener<Integer>) change -> {
            li.set(3, li.get(0) + li.get(2));
        });
        li.set(2, 3);
        System.out.println(li);

它显然有效,但它给了我许多我不理解的错误。

谢谢!

1 个答案:

答案 0 :(得分:1)

从根本上讲,您似乎期望以下几点:

IntegerProperty property = new SimpleIntegerProperty(5);
int i = property.get();
property.set(10);
System.out.println(i);

打印出10而不是5。在Java中,因为Java is always pass-by-value,所以不会发生这种情况。将值添加到ObservableList时也是如此;您所做的全部工作就是获取当时属性的值,并将其添加到列表中。之后,该属性和列表是完全独立的实体。

没有观察Java变量变化的基本方法。为了通知更改,必须有实现该行为的代码。 IntegerProperty基本上只是int周围的包装器,它拦截更改值的代码并将更改通知给观察者。像这样:

public void set(int newValue) {
    this.value = newValue;
    notifyObservers();
}

注意:IntegerProperty的实际实现要复杂得多。

ObservableList也是如此。所有的核心实现都只是常规List的包装,而ObservableList只是拦截调用并通知观察者更改。这就是为什么,如果您使用List包装自己的FXCollections.observableList(List),则无法再直接修改List,因为它绕过了包装ObservableList,因此不会发生更改事件被解雇。

如果您想在ObservableList更改时更新IntegerProperty,则必须向IntegerProperty添加一个侦听器,以适当地更新ObservableList。如果要通过ObservableList了解对包含元素的更改,则需要使用an extractor-请参阅this answer


  

它显然有效,但它给了我许多我不理解的错误。

忽略“ 显然有效”和“ 给我很多错误”之间的矛盾,您实际上并没有提供所得到的错误。没有这些错误,很难知道出了什么问题。但是,您遇到以下情况(可能与您的错误有关,也可能与您的错误无关):

li.addListener((ListChangeListener<Integer>) change -> {
    li.set(3, li.get(0) + li.get(2));
});

这正在修改引发更改事件的ObservableList。您must not do this

  

警告::此类直接访问源列表以获取有关更改的信息。
  当列表上发生另一个更改时,这有效地使Change对象无效。
  因此,在其他线程上使用此类是不安全的。
  这也意味着无法在侦听器内部修改源列表,因为这会使所有后续侦听器的Change对象失效。