Обобщения Java - почему «расширяет T» разрешено, но не «реализует T»? - PullRequest
279 голосов
/ 10 июня 2009

Интересно, есть ли в Java особая причина использования всегда "extends", а не "implements" для определения границ параметров типа.

Пример:

public interface C {}
public class A<B implements C>{} 

запрещено, но

public class A<B extends C>{} 

правильно. В чем причина?

Ответы [ 7 ]

320 голосов
/ 10 июня 2009

В родовом языке ограничений нет семантического различия между тем, реализует ли класс или расширяет. Возможные ограничения: "extends" и "super" - то есть, может ли этот класс работать с присваиваемым этому другому (extends) или этот класс присваивается из этого (super).

56 голосов
/ 03 ноября 2016

Ответ: здесь :

Чтобы объявить параметр ограниченного типа, перечислите имя параметра типа, затем ключевое слово extends и его верхняя граница […]. Обратите внимание, что в этом контексте extends используется в общем смысле для обозначения либо extends (как в классах), либо implements (как в интерфейсах).

Итак, у вас это есть, это немного сбивает с толку, и Oracle это знает.

17 голосов
/ 10 июня 2009

Возможно, потому что для обеих сторон (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 , но с дополнительными возможностями. Здесь важны возможности, а не реализация.

7 голосов
/ 31 июля 2012

Вот более сложный пример того, где разрешены расширения и, возможно, что вы хотите:

public class A<T1 extends Comparable<T1>>

7 голосов
/ 10 июня 2009

Возможно, базовый тип является универсальным параметром, поэтому фактический тип может быть интерфейсом класса. Рассмотрим:

class MyGen<T, U extends T> {

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

5 голосов
/ 22 января 2016

Это какой-то произвольный, какой из терминов использовать. Это могло быть в любом случае. Возможно, разработчики языка думали, что «расширяет» как самый фундаментальный термин, и «внедряет» как особый случай для интерфейсов.

Но я думаю, implements имело бы немного больше смысла. Я думаю, это больше говорит о том, что типы параметров не должны быть в отношениях наследования, они могут быть в любом виде отношения подтипа.

Глоссарий Java выражает аналогичный вид .

1 голос
/ 25 мая 2019

Мы привыкли к

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)

за исключением того, что нам также нужно было бы позаботиться о implements, что еще более усложнит ситуацию.

Я полагаю, что это главная причина, по которой extends ClassOrInterfaceType используется вместо extends ClassType и implements InterfaceType - для простоты в рамках сложной концепции. Проблема в том, что у нас нет подходящего слова для обозначения extends и implements, и мы определенно не хотим вводить его.

<T is ClassTypeA>
<T is InterfaceTypeA>

Хотя extends вносит некоторую путаницу, когда он связан с интерфейсом, это более широкий термин, и его можно использовать для описания обоих случаев. Попробуйте настроить свой разум на концепцию расширения типа (не расширения класса , а не реализации интерфейса ). Вы ограничиваете параметр типа другим типом , и не имеет значения, что это за тип на самом деле. Имеет значение только то, что это верхняя граница и его супертип .

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...