Кто расширяет интерфейсы? И почему?

20

AFAIK, мой класс extendsродительских классов и implementsинтерфейсов. Но я сталкиваюсь с ситуацией, когда я не могу использовать implements SomeInterface. Это объявление универсальных типов. Например:

public interface CallsForGrow {...}

public class GrowingArrayList <T implements CallsForGrow>  // BAD, won't work!
                              extends ArrayList<T> 

Здесь использование implementsсинтаксически запрещено. Сначала я подумал, что использование интерфейса внутри <> вообще запрещено, но нет. Это возможно, я должен использовать только extendsвместо implements. В результате я «расширяю» интерфейс. Этот другой пример работает:

public interface CallsForGrow {...}

public class GrowingArrayList <T extends CallsForGrow>  // this works!
                              extends ArrayList<T> 

Для меня это выглядит как синтаксическое несоответствие. Но, может быть, я не понимаю некоторые особенности Java 6? Есть ли другие места, где я должен расширять интерфейсы? Должен ли интерфейс, который я имею в виду расширить, иметь какие-то особые функции?

Гангнус
источник

Ответы:

25

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

И нет причин усложнять синтаксис только потому, что в одном другом месте (где вы на самом деле реализуете интерфейс) различие между классами и интерфейсами имеет значение (например, если вы implementинтерфейс, вам нужно реализовать все методы, которые он определяет, но вы не нужно, если вы extend(неабстрактный) класс).

Предполагая на мгновение, что вам придется написать implementsздесь, вам также понадобится отдельный синтаксис для enumзначений (вместо простого написания <E extends Enum<E>>) и аннотаций (которые вы можете легко объявить, используя <A extends Annotation>).

Единственное место, где вам нужно писать, implementsэто точка, где вы на самом деле реализуете интерфейс. В этой точке (и только в этой точке) разница важна, потому что вы должны реализовать методы, определенные в интерфейсе. Для всех остальных не имеет значения, является ли данный Aкласс базовым классом или реализованным интерфейсом B: это супертип, и это все, что имеет значение.

Также обратите внимание, что есть еще одно место, где вы используете extendsс интерфейсами:

interface A {
}

interface B extends A {
}

На данный момент implementsбыло бы неправильно, потому B что не реализует A .

Йоахим Зауэр
источник
Если мы будем использовать вашу логику, мы должны всегда использовать 'extends SomeInterface' , а не только в обобщениях.
Гангнус
2
@Gangnus: нет, потому что для разработчика есть конкретное различие между extendsи implements, просто если смотреть на проблему с точки зрения системы типов, то нет никакой разницы.
Йоахим Зауэр
1
Извините, я не понимаю вашу мысль. --1. Почему мы должны использовать «чисто перспективу системы типов» в одном случае, а не в другом? --2. Почему синтаксические требования меняются в этих разных местах? Не могли бы вы объяснить это, пожалуйста. В ответ, если возможно.
Гангнус
1
@Gangnus: кто сказал, что Tэто класс? Tможет ссылаться на тип интерфейса или enumтип.
Йоахим Зауэр
1
Исходя из C #, все это обсуждение смешно. мы обозначаем супертипы типа через :. и под прикрытием интерфейс является и всегда был абстрактным классом с ограничением, состоящим только из невыполненных abstractчленов virtual ( ), чтобы обеспечить множественное наследование. нет буквально никакой разницы между implementsи extends. оба они могут быть заменены одним и тем же словом ( extends) или произвольным символом ( :), и ничего не будет потеряно.
Сара
5

Когда Java 5 и, в частности, дженерики, изначально были доступны для разработчиков, которые зарегистрировали интерес, синтаксис был совершенно другим. А не так Set<? extends Foo>и Set<? super Bar>было Set<+Foo>и Set<-Foo>. Тем не менее, обратная связь заключалась в том, что неясно, +означает ли это более конкретный или более широкий (больше классов) . Sun отреагировала на эту обратную связь, изменив синтаксис, но в рамках ограничения не вводить новые ключевые слова, что было бы проблемой для обратной совместимости.

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

Тем не менее, это изменение не влияет на основные принципы интерфейса, и оно не содержит специальных интерфейсов, которые расширены по-новому.

Питер Тейлор
источник
+1. Я вижу и согласен. Но Йоахим Зауэр нашел мое ошибочное мнение, что T - это обязательно класс. Итак, ответ его. Ваше понимание на один (или 2) этаж выше :-). Моя проблема была более примитивной. В любом случае спасибо за мое развитие.
Гангнус
2

Есть недостатки как в том, чтобы разрешать, так и в запрещении такого синтаксиса, а те, которые разрешают , намного выше.

Просто подумай об этом.

Разделение интерфейса и реализации является одной из основных идиом программирования. Из-за этого синтаксис, позволяющий записать «интерфейс реализует что-то» , будет примерно таким же плохим, как и использование знака «плюс» для обозначения умножения операндов.

комар
источник
Ok. Итак, я действительно чего-то не понимаю. Я посчитал это очень вероятным. Но вы не объяснили проблему вообще, извините. T является представлением класса. Почему в одном месте я использую T extends, а в другом T реализует?
Гангнус
@Gangnus в приведенном вами примере T относится к параметру типа, который не обязательно является классом - посмотрите, что уже сказал вам Иоахим . Принятие орудий для этого приведет к тому же беспорядку, о котором я упоминал
gnat
Да, я уже видел его комментарий. Он будет отмечен как ответ, когда вставлен в ответ. Пока вы оба не поблагодарите меня и +1.
Гангнус
-1

Нужно понимать программирование на основе интерфейса как следующий шаг при понимании интерфейса. Это говорит о том, что является фактическим использованием интерфейса. Какую роль он играет в программе Java (или любого другого языка).

Дипак
источник
2
Как ваш ответ решает проблемы ОП? Пожалуйста, измените свой ответ, чтобы быть более четким