Я пытаюсь использовать интерфейс с JavaFX ListView, чтобы можно было отображать несколько типов объектов в списке в разных точках приложения (разные типы объектов на разных графических интерфейсах GUI. Я определил ListView в моем классе контроллера JavaFX как:
@FXML private static ListView<? extends ListDisplayObj> lvLeftBarItems;
и ListDisplayObj
- это простой интерфейс:
public interface ListDisplayObj
{
public String getListDisplayString();
}
У меня есть метод уровня базы данных, который получает список объектов, которые будут отображаться на основе заданного ключа, - метод определяется как:
public ObservableList<? extends ListDisplayObj> getListObjectsForKey(String selectedKey)
{
...
}
Позже в обработчике событий контроллера (или в методе initialize()) я пытаюсь инициализировать ListView с помощью ObservableList следующим образом:
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
Какие-либо предложения? Я не уверен, как это решить. Я пробовал варианты использования raw Object (который реализует ListDisplayObj) вместо <? extends ListDisplayObj>
<? extends ListDisplayObj>
, просто вернув <ListDisplayObj>
vs <? extends ListDisplayObj>
<? 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: какие методы и поля доступны/недоступны через ссылочную переменную подстановочного параметра для более подробного объяснения.
Что касается вашего кода, просто замените объявление lvLeftBarItems
на lvLeftBarItems
общий:
ListView<ListDisplayObj> lvLeftBarItems;
ListView<ListDisplayObj> lvLeftBarItems;
и попытался использовать ObservableList<ListDisplayObj> = MyObjectManager.getListObjectsForKey(selectedKey);
который возвращает ObservableList <ConcreteObject>, где ConcreteObject implements ListDisplayObj
. Обратите внимание, что это интерфейс (реализует, а не расширяет). В этом случае компилятор отклоняет присвоение коллекции из служебного метода, говоря, что типы несовместимы. Возможно, я должен опубликовать этот вопрос отдельно.