В чем разница между? и T в подписи класса и метода?

почему

public interface ArrayOfONEITEMInterface <T extends ONEITEMInterface>{
    public List<T> getONEITEM();
}

скомпилировать, но не

public interface ArrayOfONEITEMInterface <? extends ONEITEMInterface>{
    public List<?> getONEITEM();
}

В чем разница? и T в подписи класса и метода?

Ответ 1

? является подстановочным знаком и означает любой подкласс ONEITEMInterface, включающий в себя.

T - это конкретная реализация ONEITEMInterface в этом случае.

Так как ? является подстановочным знаком, между вашим ? в объявлении класса и ? в объявлении метода нет никакой связи, поэтому он не будет компилироваться. Просто List<?> getONEITEM(); будет компилироваться.


первый сценарий означает, что весь класс может обрабатывать ровно один тип Bar для каждого экземпляра.

interface Foo<T extends Bar> {
     List<T> get();
}

второй сценарий позволяет каждому экземпляру работать с любым подтипом Bar

interface Foo {
     List<? extends Bar> get()
}

Ответ 2

Предложение <T extends ONEITEMInterface> объявляет параметр типа с именем T. Это позволяет вашему типовому типу ArrayOfONEITEMInterface ссылаться на параметр в другом месте. Например, вы можете объявить метод типа void add(T t).

Не называя параметр типа, как бы вы на него ссылались? Если вы никогда не ссылаетесь на параметр типа, почему ваш тип является общим в первую очередь? Например, вам не нужен параметризованный тип, чтобы сделать что-то вроде этого:

public interface ArrayOfONEITEMInterface {
    List<? extends ONEITEMInterface> getONEITEM();
}

Не имеет смысла объявлять анонимный параметр типа, поэтому он является синтаксически незаконным.

Ответ 3

T является заполнителем для типа, который будет предоставляться классом реализации или экземпляра.

? является заполнителем, говорящим: "Я не знаю и не забочусь о том, что такое общий тип" обычно используется, когда работа, которую вы будете делать на объекте-контейнере, не должна знать тип.

Причина, по которой вы не можете использовать '?' в определении класса/интерфейса, потому что там указано значение, определяющее имя заполнителя (и тип будет предоставлен в другом месте). Ввод "?" не имеет смысла.

Кроме того, заполнитель не должен быть T, он может любой стандартной переменной Java. По соглашению, это один главный символ, но не обязательно.

Ответ 4

? позволяет вам иметь список Неизвестных типов, где, когда T требует определенного типа.