ReadOnlyDoubleProperty

ReadOnlyDoubleProperty

关于泛型,有人告诉我强制转换很糟糕,通常有某种方法可以完全消除强制转换,以便编译器在检查程序时尽力而为。在ChangeListener上添加ReadOnlyDoubleProperty似乎违反了这一理想。这是API中的缺陷,还是规则的例外,还是实际上有某种方法可以使此代码看起来不错?

nodeA.heightProperty().addListener(new ChangeListener<Number>() {
    @Override
    public void changed(ObservableValue< ? extends Number > observable,
                        Number oldValue,
                        Number newValue ) {
        final double ov = oldValue.doubleValue();
        final double nv = newValue.doubleValue();
        @SuppressWarnings("unchecked")
        final ObservableValue<Double> ob = ( ObservableValue< Double > ) observable;
        // do stuff
    }
});


首先,我可以在ChangeListener上使用的最具体的类型参数是Number。我应该可以使用Double!这是DoubleExpression!由于这个问题,我必须解压缩changed方法的参数。请在此处帮助减少行数。 Lambda可以减少行数,但是我要特别询问泛型。

最佳答案

tl; dr:使用asObject

首先请注意,在您发布的示例中,根本没有理由引用observable参数,因为它必须与nodeA.heightProperty()相同。所以您可以简单地消除

nodeA.heightProperty().addListener(new ChangeListener<Number>() {
    @Override
    public void changed(ObservableValue< ? extends Number > observable,
                        Number oldValue,
                        Number newValue ) {
        final double ov = oldValue.doubleValue();
        final double nv = newValue.doubleValue();

        // do stuff with nodeA.heightProperty() ...
    }
});


这一点也不罕见:实际上,我一直不需要使用传递给此方法的可观察对象,因为我始终使用相同的模式。

至于ReadOnlyDoubleProperty是否实现ObservableValue<Number>而不是ObservableValue<Double>的事实,这取决于您的观点,这是便利功能还是设计缺陷。 (请参见讨论here,以及其他内容...)。解决方法是在asObject()上调用ReadOnlyDoubleProperty,它返回双向绑定到ReadOnlyObjectProperty<Double>ReadOnlyDoubleProperty并实现ObservableValue<Double>

nodeA.heightProperty().asObject().addListener(new ChangeListener<Double>() {
    @Override
    public void changed(ObservableValue< ? extends Double > observable,
                        Double oldValue,
                        Double newValue ) {
        final double ov = oldValue.doubleValue();
        final double nv = newValue.doubleValue();

        // do stuff
    }
});


(取消装箱还会使ovnv在上述内容中多余。)

当然,您可以使用lambdas使其变得更好:

nodeA.heightProperty().asObject().addListener((obs, oldValue, newValue) -> {
    // obs is now an ObservableValue<Double>, if you need it
    // oldValue is a Double, which can be treated as a double via unboxing
    // similarly newValue is a Double

    // do stuff..
});

09-26 20:22