1

ReadOnlyBooleanWrapper使用 . 绑定两个对象时,我遇到了一个非常奇怪的行为Binding.or。即,当我b1.set(true)对第一个参数进行处理时,结果不正确(仍然是错误的)。

这是一个简单的单元测试(失败):

@Test
public void testReadOnlyBooleanWrapper() {
    // Fails!!!
    testOr(new ReadOnlyBooleanWrapper(false), new ReadOnlyBooleanWrapper(false));
}

public void testOr(BooleanProperty b1, BooleanProperty b2) {
    BooleanExpression or = b1.or(b2);

    assertEquals(or.get(), b1.get() || b2.get());
    b1.set(true);
    assertEquals(or.get(), b1.get() || b2.get());
    b1.set(false);
    assertEquals(or.get(), b1.get() || b2.get());
}

请注意,相同的测试可以SimpleBooleanProperties正常工作:

@Test
public void testSimpleBooleanProperty() {
    // Passes
    testOr(new SimpleBooleanProperty(false), new SimpleBooleanProperty(false));
}

我可能在这里遗漏了一些要点并滥用了属性,因为我无法想象实现中会出现这样的错误!:)

感谢任何想法如何解释它!

更新:

您的回答和评论使我走上了正确的轨道:)我还没有解决方案,但我注意到如果我将其绑定orReadOnlyProperties(应该被暴露)而不是包装器本身,那么测试通过:

@Test
public void testOrReadOnly() {
    ReadOnlyBooleanWrapper b1 = new ReadOnlyBooleanWrapper(false);
    ReadOnlyBooleanWrapper b2 = new ReadOnlyBooleanWrapper(false);

    BooleanExpression or = b1.getReadOnlyProperty().or(b2.getReadOnlyProperty());

    System.out.println("Condition " + or.get());
    assertEquals(or.get(), b1.get() || b2.get());
    b1.set(true);
    System.out.println("Condition " + or.get());
    assertEquals(or.get(), b1.get() || b2.get());
    b1.set(false);
    System.out.println("Condition " + or.get());
    assertEquals(or.get(), b1.get() || b2.get());
}

这让我认为内部可读写属性与只读属性之间的同步以某种方式被破坏了(?)

从有关文档的文档中ReadOnlyBooleanWrapper

该类提供了一个方便的类来定义只读属性。它创建了两个同步的属性。一个属性是只读的,可以传递给外部用户。另一个属性是可读写的,只能在内部使用。

4

1 回答 1

2

这是一个错误(imo)。

发生的事情是or绑定的实现实现了“或”的短路(这是在Bindings.java中):

    @Override
    public void invalidated(Observable observable) {
        final BooleanOrBinding binding = ref.get();
        if (binding == null) {
            observable.removeListener(this);
        } else {
            // short circuit invalidation. This BooleanBinding becomes
            // only invalid if the first operator changes or the
            // first parameter is false.
            if ((binding.op1.equals(observable) || (binding.isValid() && !binding.op1.get()))) {
                binding.invalidate();
            }
        }
    }

实现此功能的侦听器被添加到 : 中的每个操作数中,or但是,ReadOnlyBooleanWrapper将侦听器委托给它的ReadOnlyBooleanProperty(来自ReadOnlyBooleanWrapper.java):

@Override
public void addListener(InvalidationListener listener) {
    getReadOnlyProperty().addListener(listener);
}

因此在短路实现中,binding.op1.equals(observable)false(因为一个是ReadOnlyBooleanWrapper,另一个是它的ReadOnlyBooleanProperty)。所以这里的逻辑是(错误地)假设第二个运算符已经改变。由于第一个运算符具有 value true,因此实现的结论是对 的评估or不能改变,因此不会触发失效。因此,您or不会被重新评估。

正如您所发现的,解决方法是ReadOnlyBooleanProperty在计算绑定时使用包装。我建议你报告这个错误。

于 2015-09-29T15:37:17.600 回答