Хто розширює інтерфейси? І чому?


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 .


Якщо ми будемо використовувати вашу логіку, ми повинні використовувати "розширює SomeInterface" завжди , не тільки в генеріках.
Gangnus

2
@Gangnus: ні, тому що для виконавця є конкретна різниця між, extendsі implementsсаме тоді, коли дивишся на проблему з точки зору чистої системи типу, різниці немає.
Йоахім Зауер

1
Вибачте, я не розумію вашої думки. --1. Чому ми повинні використовувати "чисту перспективу системи типу" в одному випадку, а не в іншому? --2. Чому синтаксичні вимоги змінюються в цих різних місцях? Чи можете ви пояснити це, будь ласка. У відповідь, якщо це можливо.
Gangnus

1
@Gangnus: хто каже, що Tце клас? Tможе посилатися на тип інтерфейсу чи enumтип.
Йоахім Зауер

1
що йде від C #, вся ця дискусія є смішною. позначимо суперпертипи типу за допомогою :. і під обкладинками інтерфейс є і завжди був абстрактним класом з обмеженням, що містить лише нереалізовані віртуальні ( abstract) члени, щоб забезпечити багаторазове успадкування. між implementsі та буквально немає різниці extends. вони можуть бути замінені одним і тим же словом ( extends) або яким-небудь довільним символом ( :), і нічого не буде втрачено.
сара

5

Коли Java 5, зокрема дженерики, спочатку була доступна розробникам, які зареєстрували інтерес, синтаксис був зовсім іншим. Замість Set<? extends Foo>і Set<? super Bar>це було Set<+Foo>і Set<-Foo>. Однак відгуки полягали в тому, що не було зрозуміло, чи +означає це більш конкретний чи ширший (більше класів) . Sun відповів на цей зворотній зв’язок, змінивши синтаксис, але в рамках обмеження не вводити нові ключові слова, що могло б бути проблемою для зворотної сумісності.

Результатом є те, що жоден не є цілком природним. Як ви зауважуєте, extendsперевантажений розмовами про класи, що розширюють інтерфейси, що не є мовою, що використовується в інших контекстах; і superперевантажений, щоб означати "є надкласом", що є протилежним напрямком взаємозв'язку, вираженим раніше ключовим словом, тобто посилаючись на суперклас.

Однак на основи того, що інтерфейс не впливає, ця зміна не впливає, і він не вводить спеціальних інтерфейсів, які розширюються по-новому.


+1. Я бачу і погоджуюсь. Але Йоахім Зауер виявив моє помилкове думку, що Т - це обов'язково клас. Отже, відповідь його. Ваше розуміння на один (або 2) поверхи вище :-). Моя проблема була більш примітивною. Все одно дякую за мій розвиток.
Gangnus

2

У недопущенні та забороні такого синтаксису є недоліки, а дозволів - набагато більше.

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

Поділ інтерфейсу та реалізації є однією з основних ідіом програмування. Через це синтаксис, що дозволяє написати "інтерфейс щось реалізує", був би таким же поганим, як один, використовуючи знак плюс для позначення множення операндів.


Добре. Отже, я справді щось не розумію. Я вважав це дуже ймовірним. Але ви зовсім не пояснили проблему, вибачте. Т - представлення класу. Чому в одному місці я використовую T-розширення, а в іншому T-реалізацію?
Gangnus

@Gangnus у наведеному вами прикладі T посилається на параметр типу, який не обов'язково є класом - подивіться, що Йоахім вам уже сказав . Якщо дозволити інструменти для цього, то це призведе до того ж безладу, про який я згадав
гнат

Так, я вже бачив його коментар. Він буде позначений як відповідь, коли поставлений у відповідь. Поки ви обидва дякуєте та +1.
Gangnus

-1

Треба розуміти програмоване керування інтерфейсом як наступний крок, розуміючи інтерфейс. Він розповідає, яке фактичне використання інтерфейсу. Яку роль він відіграє в програмі Java (або будь-якій іншій мові).


2
Як ваша відповідь вирішує проблеми ОП? Будь ласка , змініть свій відповідь , щоб бути більш ясним.
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.