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

Поскольку интерфейсы - это просто классы, за исключением того, что они не имеют атрибутов или реализаций. Единственное использование ключевого слова "реализует" - позволить классу наследовать несколько интерфейсов, но не несколько классов, и мы можем видеть это в коде. Я не знаю, укажут ли они это в будущем, но это не обязательно.