我正在尝试将接口与JavaFX ListView一起使用,以允许多个对象类型显示在列表中的应用程序的不同位置(不同GUI屏幕上的不同对象类型。我在JavaFX控制器类中将ListView定义为:

@FXML private static ListView<? extends ListDisplayObj> lvLeftBarItems;


ListDisplayObj是一个简单的界面:

public interface ListDisplayObj
{
    public String getListDisplayString();
}


我有一个数据库级方法,该方法基于给定的键获取要显示的对象列表-该方法定义为:

public ObservableList<? extends ListDisplayObj> getListObjectsForKey(String selectedKey)
{
    ...
}


稍后在控制器事件处理程序(或initialize()方法)中,我尝试使用ObservableList初始化ListView,如下所示:

ObservableList<? extends ListDisplayObj> ol = MyObjectManager.getListObjectsForKey(selectedKey);
lvLeftBarItems.setItems(ol);


lvLeftBarItems.setItems(ol)调用生成以下编译器错误(在Netbeans中):

incompatible types: ObservableList<CAP#1> cannot be converted to ObservableList<CAP#2>
  where CAP#1,CAP#2 are fresh type-variables:
    CAP#1 extends ListDisplayObj from capture of ? extends ListDisplayObj
    CAP#2 extends ListDisplayObj from capture of ? extends ListDisplayObj


有什么建议么?我不确定如何解决此问题。我尝试了使用原始对象(实现ListDisplayObj)而不是<? extends ListDisplayObj>的变体,只是返回了<ListDisplayObj> vs <? extends ListDisplayObj>等,没有运气。

最佳答案

当拥有一个元素类型为X的列表时,可以存储任何类型为X或X的子类的对象。

ListView<? extends ListDisplayObj> lvLeftBarItems;


该声明意味着lvLeftBarItems是一个ListView,其内容是ListDisplayObj的一些未指定子类,将其命名为CAP#1(我知道它不是有效的类名,但为了示例目的而将其传递)。

您也试图添加一个元素,其类型在技术上也未指定为ListDisplayObj的子类,但可以将其命名为CAP#2。

现在假设CAP#1扩展了ListDisplayObj,而CAP#2扩展了ListDisplayObj,那么很明显,您无法将CAP#1的实例强制转换为CAP#2或反之,因此,您也无法强制转换CAP#1到CAP#2的列表,这正是编译器在表示“无法将ObservableList转换为ObservableList”时的含义-这些列表具有不同的不兼容类型,因为列表项具有不同的不兼容类型。

检查GenericsFAQ: Which methods and fields are accessible/inaccessible through a reference variable of a wildcard parameterized type以获得更详细的说明。

对于您的代码,只需将lvLeftBarItems的声明替换为非通配符泛型即可:

ListView<ListDisplayObj> lvLeftBarItems;

08-06 15:30