我正在尝试将接口与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;