новый список <A &? расширяет B> (); - PullRequest
0 голосов
/ 27 апреля 2018

Если вы знаете, как запустить строку заголовка, просто прокрутите вниз до tl; dr или напишите ответ!

Я написал остальную часть текста, чтобы избежать проблемы XY . Когда это будет сделано, уже не имеет значения.


Контекст

Я хочу создать объект, который принимает универсальный (Список, Карта, что угодно).

Объекты в списке должны удовлетворять 2 критериям:

  1. с mymethod() (что я понял из создания интерфейса, имеющего это в качестве заголовка метода)
  2. Расширение JComponent

Как я пытался сделать эту работу:

  1. Я создал несколько классов, каждый из которых реализует MyInterface и расширяет JComponent (его подклассы). Вот где я запускаю свою проблему с заголовком: new List<MyInterface extends JComponent);
  2. Другая идея: создание абстрактного класса (который соответствует всем критериям) вместо интерфейса. Проблема: конкретные классы, которые мне нужны, не расширяют один и тот же класс.
  3. Я думал о Дженерике, как: public abstract class MyClass<X extends JComponent> extends X, но это не может работать - по понятным причинам. (например, я должен реализовать абстрактные методы из суперкласса, но если это универсальный, я не могу знать сейчас.)

ТЛ; др

Я столкнулся с проблемой, которую легко можно было бы решить, если бы вы могли заставить эту строку работать:

new List<A extends B>();

или, представленный @khelwood: новый список ();

где:

  • A - это интерфейс (как я мог бы объявить new List<MyInterface>()
  • и любой элемент расширяется ? extends B (пример: это может быть JTextField или JTextArea или что угодно, , но это должен быть (подкласс) JComponent (JComponent = B))

Ответы [ 3 ]

0 голосов
/ 27 апреля 2018

Вы говорите, что:

Другая идея: создание абстрактного класса (который соответствует всем критериям) вместо интерфейса. Проблема: конкретные классы, которые мне нужны, не расширяют один и тот же класс.

но в то же время вы говорите, что они распространяются JComponent. Единственная возможность для этого состоит в том, что все они транзитивно расширяются JComponent. Таким образом, в какой-то момент вверх по иерархии наследования происходит прямое наследование от JComponent.

Если это все еще ваш код, то здесь вы можете ввести другой класс вместо JComponent, который расширяет JComponent и реализует ваш интерфейс.

Если нет, то я думаю, что это невозможно сделать, используя только синтаксис.

0 голосов
/ 27 апреля 2018

Я не думаю, что система типов позволяет вам делать именно то, что вы хотите, и получать безопасность типов во время компиляции.

Одним из приближений является следующее:

List<JComponent> componentList = new ArrayList<>();
List<MyInterface> myInterfaceList = (List) componentList;

Если вы не возражаете против предупреждения во время компиляции, у вас теперь есть два представления в одном и том же списке: одно показывает содержимое как JComponent, а другое как MyInterface.

Вы можете добавить объекты в любое представление, а затем прочитать их из представления, предоставляющего правильный тип для контекста.

Естественно, когда вы добавляете объект, компилятор не проверяет, что вставленный объект подклассов JComponent и MyInterface. Это ваша ответственность.

Если вы хотите больше безопасности типа (во время выполнения), вы можете пойти по этому пути:

List rawList = new ArrayList();
List checkedList = Collections.checkedList(rawList, JComponent.class);
List doublyCheckedList = Collections.checkedList(checkedList, MyInterface.class);
List<JComponent> componentList = doublyCheckedList;
List<MyInterface> myInterfaceList = doublyCheckedList;

Если вы вставляете только в doublyCheckedList, во время выполнения список проверит, что вставленные объекты подклассы JComponent и MyInterface. При чтении вы можете использовать два представления, как в моем предыдущем фрагменте.

0 голосов
/ 27 апреля 2018

Если вы хотите иметь возможность создавать список вещей, которые расширяют JComponent, реализовывать ваш интерфейс и добавлять вещи в такой список, вам нужно определить конкретный тип, который реализует оба:

List<ThatType> list = new ArrayList<>();
list.add(new ThatType());

Вы можете объявить переменную типа для этого, чтобы написать универсальный метод:

<T extends JComponent & YourInterface> void something(T thing) {
  // ...
}

<Something extends SomethingElse> работает только в объявлениях переменных типа.

Более того, вы не создаете список Somethings that extends SomethingElse: вы создаете список Somethings, и зависит ли Something extends SomethingElse от того, как определены эти типы.

Чтобы сделать это более конкретным, вы не создаете new List<String extends Object>: вы делаете List<String>, а String оказывается расширением Object.

Вам необходимо правильно объявить переменные типа, например ::

class Foo<B> {
  <A extends B> List<A> list() {
    return new List<>();
  }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...