Java generics - почему "extends T" разрешен, но не "реализует T"?
Интересно, есть ли в Java особая причина для использования всегда "extends
", а не "implements
" для определения границ типовых параметров.
Пример:
public interface C {}
public class A<B implements C>{}
запрещено, но
public class A<B extends C>{}
является правильным. В чем причина этого?
Ответы
Ответ 1
В обобщенном языке ограничений нет семантической разницы между тем, реализуется ли класс "реализует" или "расширяет". Возможности ограничения - это "extends" и "super", то есть этот класс должен работать с назначаемым к другому (extends), или этот класс можно назначить из этого (супер).
Ответ 2
Ответ находится в здесь:
Чтобы объявить параметр ограниченного типа, укажите имя параметра типа, за которым следует ключевое слово extends
, а затем его верхняя граница [...]. Обратите внимание, что в этом контексте расширения в общем смысле означают либо extends
(как в классах), либо implements
(как в интерфейсах).
Итак, у вас это есть, это немного запутанно, и Oracle это знает.
Ответ 3
Возможно, потому что для обеих сторон (B и C) применим только тип, а не реализация.
В вашем примере
public class A<B extends C>{}
B также может быть интерфейсом. "extends" используется для определения суб-интерфейсов, а также подклассов.
interface IntfSub extends IntfSuper {}
class ClzSub extends ClzSuper {}
Я обычно думаю о том, что "Sub extends Super" используется как "Sub", как Super, но с дополнительными возможностями ", а" Clz реализует Intf ", поскольку" Clz - это реализация Intf ". В вашем примере это будет соответствовать: B похож на C, но с дополнительными возможностями. Здесь важны возможности, а не реализация.
Ответ 4
Возможно, базовый тип является общим параметром, поэтому фактический тип может быть интерфейсом класса. Рассмотрим:
class MyGen<T, U extends T> {
Также из клиентского кода перспективные интерфейсы почти неотличимы от классов, тогда как для подтипа важно.
Ответ 5
Вот более привлекательный пример того, где разрешены расширения и, возможно, что вы хотите:
public class A<T1 extends Comparable<T1>>
Ответ 6
Это своего рода произвольный, какой из терминов использовать. Это могло быть в любом случае. Возможно, разработчики языка думали, что "расширяет" как самый фундаментальный термин, и "внедряет" как особый случай для интерфейсов.
Но я думаю, что implements
будут иметь больше смысла. Я думаю, это больше говорит о том, что типы параметров не должны быть в отношениях наследования, они могут быть в любом виде отношений подтипа.
Глоссарий Java выражает похожую точку зрения.
Ответ 7
"Расширяется" в этом контексте означает, как реализует в интерфейсах и расширяется в классах. Вот еще объяснение
Ответ 8
Мы привыкли к
class ClassTypeA implements InterfaceTypeA {}
class ClassTypeB extends ClassTypeA {}
и любое небольшое отклонение от этих правил сильно смущает нас.
Синтаксис привязки типа определяется как
TypeBound:
extends TypeVariable
extends ClassOrInterfaceType {AdditionalBound}
(JLS 12> 4.4. Типовые переменные> TypeBound
)
Если бы мы изменили его, мы наверняка добавили бы случай с implements
TypeBound:
extends TypeVariable
extends ClassType {AdditionalBound}
implements InterfaceType {AdditionalBound}
и в конечном итоге с двумя одинаково обработанными предложениями
ClassOrInterfaceType:
ClassType
InterfaceType
(JLS 12> 4.3. Типы и значения ClassOrInterfaceType
> ClassOrInterfaceType
)
за исключением того, что мы также должны были бы позаботиться о implements
, которые еще больше усложнят ситуацию.
Я полагаю, что это основная причина, почему extends ClassOrInterfaceType
используется вместо extends ClassType
и implements InterfaceType
- чтобы все было просто в рамках сложной концепции. Проблема в том, что у нас нет подходящего слова для обозначения как extends
и implements
и мы определенно не хотим вводить их.
<T is ClassTypeA>
<T is InterfaceTypeA>
Хотя extends
вносит некоторую путаницу, когда идет речь о интерфейсе, это более широкий термин, и его можно использовать для описания обоих случаев. Попробуйте настроить свой разум на идею расширения типа (не расширения класса, не реализации интерфейса). Вы ограничиваете параметр типа другим типом, и не имеет значения, что это за тип на самом деле. Имеет значение только то, что это его верхняя граница и его супертип.
Ответ 9
Поскольку интерфейсы - это просто классы, за исключением того, что они не имеют атрибутов или реализаций. Единственное использование ключевого слова "реализует" - позволить классу наследовать несколько интерфейсов, но не несколько классов, и мы можем видеть это в коде. Я не знаю, укажут ли они это в будущем, но это не обязательно.