我可以拥有一个接受子类型的列表属性吗?

时间:2016-08-10 11:39:29

标签: java generics javafx

在我的应用程序中,我有一个基于抽象基本数据类型的特定数据项,具有相应的具体子类型。

我有一个UI组件,显示这些数据项的列表。我想公开基本数据类型的ListProperty(它具有我想要显示的所有公共字段),并且能够将它绑定到提供特定子类型列表的其他组件。但我似乎无法使这些列表兼容。

说明问题的代码示例:

import javafx.beans.property.ListProperty;
import javafx.beans.property.SimpleListProperty;

public class GenericTest
{
    static class BaseClass {}
    static class SubClass extends BaseClass {}

    ListProperty<SubClass> sourceList = new SimpleListProperty<>();
    ListProperty<? extends BaseClass> observingList = new SimpleListProperty<>();

    {
        observingList.bind( sourceList );
    }

}

我在bind()调用上遇到编译错误 - 不兼容的类型。我以为我理解Java泛型,但显然不是。

是否可以将列表属性与混合中的泛型绑定,还是应该寻找替代解决方案?

2 个答案:

答案 0 :(得分:2)

observingList的元素类型是“BaseClass的某个未知子类”。所以基本上你必须绑定到一个列表,其元素类型与那个特定但未知的类型兼容。

从编译器的角度来看,您可以指定observingList,例如BaseClass的不同子类,即如果你有

static class AnotherClass extends BaseClass {}

然后

observingList = new SimpleListProperty<AnotherClass>();

完全合法。

现在由于SubClass的实例不是AnotherClass的实例,因此应该清楚为什么绑定无法编译。

或许另一种看待此问题的方法是考虑尝试致电observingList.add(...)。你能合法地将这个方法传递给那个方法吗?虽然你显然不需要自己调用(因为你将它绑定到某些东西上),bind(...)的实现显然需要在某个时候调用add(...):如果你没办法要调用该方法,绑定也无法这样做。

基本上,要使绑定起作用,您需要指定类型(没有通配符)。所以,显然你可以做到

ListProperty<SubClass> observingList = new SimpleListProperty<>();

然后绑定工作,但你也可以参数化类型,例如:

public static <T extends BaseClass> ListProperty<T> createBoundList(ListProperty<T> sourceList) {
    ListProperty<T> observingList = new SimpleListProperty<>();
    observingList.bind(sourceList);
    return observingList ;
}

然后

ListProperty<? extends BaseClass> observingList = createBoundList(sourceList);

将编译。

答案 1 :(得分:0)

这是一种解决方法,而不是直接绑定(James_D的答案看起来像是正确的解决方案),但你也可以这样做......

sourceList.addListener((observable, oldValue, newValue) -> observingList.setAll(newValue));

根据我的具体情况,这对我有用,但你的里程可能会有所不同......