Захищено в інтерфейсах


111

Чому всі методи у interfaceвизначенні неявно public? Чому він не дозволяє protectedметод?


22
Дуже гарне запитання. Майже для кожної іншої речі на Яві я знайшов справжню причину для зробленого вибору, але для цього я цього не зробив. Для мене має сенс визначити захищений метод в інтерфейсі, який дозволяє іншому класу всередині того ж пакету використовувати цей метод на об'єкті реалізації, не вимагаючи цього викриття, який не може бути призначений ким-небудь, крім окрім учасники пакету, в інший світ.
Маркус А.

4
@MarkusA. Але інтерфейси працюють двосторонніми, тобто вони також можуть бути реалізовані класами поза поточним пакетом (а потім, можливо, передаються як аргументи методам всередині цього пакету). Як би клас поза поточним пакетом міг реалізувати "захищені" методи деякого публічного інтерфейсу?
MartinStettner

8
@MartinStettner: Не буде. Це був би сенс. У пакеті може бути кілька непов'язаних класів, які реалізують інтерфейс, і хочуть гарантувати будь-якому коду, що отримує посилання цього типу інтерфейсу, що він буде вести себе певним чином. Таку гарантію можна зробити набагато сильнішою, якщо зовнішній код не міг би вимагати впровадження інтерфейсу, поводячись так, як це суперечить його договору.
supercat

1
@MarkusA. ви підняли хорошу точку, ви зможете досягти цього за допомогою модульної системи Java 9
Nir Alfasi

1
якщо в інтерфейсі є protectedметод, весь клас реалізації буде розглядатися як підтип інтерфейсу. і всі ці класи МОЖУТЬ отримати доступ до захищених методів. чи не робить це protectedключовим словом методу марним? доки у нас немає ніяких способів обмежити, хто реалізує це захищене інтерфейсом ключове слово в методі, марний. виправте мене, якщо я помиляюся!
amarnath Harish

Відповіді:


67

Тому що інтерфейс повинен означати "те, що ви можете бачити поза класом". Не було б сенсу додавати непублічні методи.


16
Але чому б не було функцій, які лише члени того ж пакету, що й інтерфейс, "можуть бачити поза класом"? У мене було кілька випадків використання, коли я цього бажав.
Маркус А.

5
@MarkusA. Я усвідомлюю, що це пізно, але тоді ви можете зробити повністю abstract class, який є всім interface, і вказати, який доступ ви хочете. Зрозумівши це, ви втрачаєте перевагу від декількох реалізацій, які interfaceпотрапляють на Java, але чесно встановити контракт, який дотримується обмежень у якомусь іншому пакеті, було б непереборним і заплутаним, оскільки ви практично не мали б доступу до методу своєї власної реалізації поза цим пакетом. .
picypg

10
@pickypg Але якщо клас, який би реалізував інтерфейс, вже розширює інший клас, ви не можете змусити його розширити інший клас. Я не вважаю це заплутаним для інтерфейсу, який використовується лише всередині пакета.
Flamma

24
@Raveline, -1, тут виникає питання "чому інтерфейс повинен означати те, що ви можете бачити поза класом?" Java 8 вже дозволяє тіло методу в інтерфейсах, то чому б не дозволити також захищені абстрактні методи?
Pacerier

8
Я часто читаю це пояснення, але це неправильно ІМХО. Інтерфейс є свого роду "стандартним протоколом обміну", незалежно від того, говорити про OOP, API зв'язку або апаратне забезпечення. Порт USB на моєму ПК - це явно загальнодоступний інтерфейс. Але штифти моєї материнської плати, що знаходиться за корпусом із зафіксованим ключем, що забезпечують доступ до додаткових портів USB, явно є "захищеним" інтерфейсом. Тоді у нас є мікросхема BIOS - це також стандартизований інтерфейс, але він ніколи не оприлюднюється, лише деякі компанії знають точні деталі приватно. Тож, звичайно, інтерфейси можуть мати будь-яку видимість! Чому б не в ООП?
Foo Bar

55

Хоча часто цитується причина в тому, що "інтерфейси визначають загальнодоступні API", я вважаю, що це надмірне спрощення. (І це "пахне" круговою логікою.)

Було б безглуздо мати інтерфейси, що мають суміш модифікаторів доступу; наприклад, частково загальнодоступні та частково обмежені іншими класами в тому ж пакеті, що і інтерфейс. Насправді, в деяких випадках це може бути корисним внизу, IMO.

Насправді, я думаю, що частина міркувань щодо того, щоб зробити учасників інтерфейсу неявним публічним, полягає в тому, що це робить мову Java простішою :

  • Члени учасників публічного інтерфейсу простіші для програмістів. Скільки разів ви бачили код (класи), де модифікатори доступу методу вибиралися, здавалося б, випадковим чином? Багато "звичайних" програмістів мають труднощі зрозуміти, як найкраще керувати межами абстракції Java 1 . Додавання загальнодоступних / захищених / приватних пакетів до інтерфейсів робить їх ще складніше.

  • Члени учасників загальнодоступного інтерфейсу спрощують специфікацію мови ... і, отже, завдання для письменників-компіляторів Java та людей, які реалізують API відбиття.

Думка про те, що "інтерфейси визначають загальнодоступні API", можливо, є наслідком (або характеристикою) спрощення дизайнерського рішення щодо спрощення мови ... не навпаки. Але насправді два напрямки думки, ймовірно, розвивалися паралельно у свідомості дизайнерів Java.

У будь-якому випадку з офіційної відповіді на RFE в JDK-8179193 чітко видно, що команда дизайнерів Java вирішила 2, що дозволити protectedвикористання інтерфейсів додає складності для малої реальної вигоди. Кудос до @skomisa для пошуку доказів .

Докази в RFE вирішують це питання. Це є офіційною причиною, чому цього не було додано.


1 - Зрозуміло, програмісти з вищою зброєю не мають труднощів з цими речами, і вони можуть вітати більш багату палітру функцій контролю доступу. Але що відбувається, коли їх код передають комусь іншому для підтримки?

2 - Ви можете не погодитися з їх рішенням або викладеними ними міркуваннями, але це суперечка.


21

Я мушу сказати, що це питання було знову відкрито впровадженням методів за замовчуванням у Java 8. Проект, над яким я зараз працюю, схожий на базовий характер інтерфейсу, мав на увазі абстрактний намір від впровадження.

Є кілька випадків, коли я міг різко спростити свій код методом "захищений за замовчуванням". Виявляється, це насправді не працює, оскільки інтерфейси все ще дотримуються логіки Java 7. Звичайні захищені методи особливо не мають сенсу з вищезазначених причин; але якщо загальнодоступний загальнодоступний метод вимагає ресурсу низького рівня, який, швидше за все, не зміниться і може бути забезпечений захищеним методом, мені здається, що робота "захищена за замовчуванням" не тільки підтримуватиме чистіший код, але захистить майбутніх користувачів від випадкові зловживання.

(Це трагічно не змінює того факту, що мені все-таки потрібно надмірно ускладнювати свій код інакше непотрібними рефератами; але я маю намір вносити запит на функцію в Oracle.)


Я згоден на 100%. Абстрактні класи були розумною альтернативою до впровадження методів за замовчуванням. Однак обмеження, які вони ставлять на багаторазове успадкування, означає, що вони не є ідеальними. Інтерфейси з методами за замовчуванням зазвичай є кращою альтернативою у світі> = JDK 1.8, але оскільки вони не можуть зберігати стан, вони покладаються на визначення інших абстрактних методів для викриття стану, а це означає, що стан оприлюднюється, що не завжди є тим, що ти хочеш.
Отець Джеремі Криг

10

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

Можна використовувати абстрактні класи із захищеними абстрактними методами, але інтерфейси обмежені публічними методами та загальнодоступними статичними фінальними полями.


5
Ви заявили "тому, що інтерфейси визначають загальнодоступні API". То чому причина інтерфейсів повинна визначати лише publicAPI? Існує різниця між "внутрішньою деталлю" та "деталізацією про реалізацію", protectedу Java це, безумовно, не внутрішня деталь, оскільки зараз це публічний інтерфейс, опублікований для всіх, хто може її підкласифікувати, а це, в основному, весь світ.
Pacerier

1
Не відповідає дійсності методів Java 8 за замовчуванням.
Маріо Россі

@MarioRossi І також не відповідає дійсності методів приватного інтерфейсу Java 9.
skomisa

7

Можливо, тому, що це інтерфейс , тобто він є, щоб сказати клієнтам, що вони можуть робити з екземплярами, а не говорити їм, що вони не можуть зробити.


1
Я не бачу, чому інтерфейс не міг також сказати підкласам, що вони можуть робити, не піддаючи цю реалізацію зовнішньому світу. Це було дизайнерське рішення, яке було прийнято в той час, коли абстрактні класи можуть використовуватися як ідеальна альтернатива. Але з появою методів за замовчуванням в інтерфейсах абстрактні класи тепер є недосконалою альтернативою.
Отець Джеремі Криг

6

Я сильно вважаю, що інтерфейси повинні дозволяти захищені методи; хто сказав, що інтерфейси повинні бути видимими для всіх у всьому світі? Щодо вашої точки зору, що це може заплутати "звичайних" (читайте: некомпетентних) програмістів: стільки OOP - це належне структурування об'єктів, класів, пакетів тощо. Якщо програмісту важко робити все, що належним чином, у нього є набагато більша проблема. Java була побудована для такого типу речей.


Це не дає відповіді на запитання.
Стівен С

5

Кілька відповідей тут використовують кругові міркування, щоб пояснити, чому методи інтерфейсу не можуть бути захищені: це тому, що вони повинні бути відкритими, тому очевидно, що їх не можна захистити!

Це нічого не пояснює, але, на щастя, хтось підняв запит на вдосконалення захищених методів в інтерфейсах як помилка JDK пару років тому, що прояснює проблему:

Захищені методи в інтерфейсах: ділитися в різних пакетах

Оскільки модифікатори в Java трохи обмежені, спосіб спільного використання методів між пакетами обмежений лише публічними методами. Іноді небезпечно оприлюднювати метод, але це потрібно через відсутність належних модифікаторів. Моє рішення долає це обмеження.

Спеціалізація мови java наразі не дозволяє захищений модифікатор методів інтерфейсу. Ми можемо скористатися цим фактом і використовувати захищені для інтерфейсу методи для цієї нової функції.

Якщо метод інтерфейсу позначений захищеним, а інтерфейс реалізований класом в іншому пакеті, метод не повинен бути загальнодоступним, але також може бути приватним або принаймні захищеним пакетом. Метод видно, що колись клас оголошує його таким, що він є, і додатково видимим у вихідному пакеті інтерфейсу (та підпакетів?).

Таким чином ми могли б поділитися певними методами у добре відомих пакетах.

І це відповідь на той запит на покращення, який закрився статусом Won't fix :

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

Альтернативою, що починається в Java 9, є оприлюднення класів і методів, але всередині модуля, який має кваліфікований експорт до конкретних модулів «товариш», а не експортуватися для широкої громадськості.

Тож авторитетними виводами з цього звіту про помилку є:

  • Нинішня ситуація не зміниться; інтерфейси навряд чи коли-небудь підтримують protectedметоди.
  • Виправданням непідтримування protectedметодів в інтерфейсах є те, що це " додає складності та особливих випадків для невеликого фактичного виграшу ".
  • Оскільки у Java 9 існує альтернативний підхід для забезпечення доступу на рівні пакетів до методів. Використовуйте модульну систему платформи Java (JPMS) для " оприлюднення класів та методів, але всередині модуля, який має кваліфікований експорт до конкретних" товаришів "модулів, а не експортується для широкої громадськості ".

4

Оскільки клас реалізації повинен реалізувати ВСІ методи, заявлені у вашому інтерфейсі, що буде, якщо ваш клас реалізації був у іншому пакеті?


2

Інтерфейс Якщо ви хочете використовувати щось, як ви описали, продовжуйте працювати з абстрактними класами або вкладеними інтерфейсами.

Експерт із стилю коду щодо змінних інтерфейсів, але все ж стосується методів:

Змінні інтерфейсу неявно є загальнодоступними, оскільки інтерфейси призначені для надання інтерфейсу програмування прикладних програм (API), який повністю доступний програмістам Java для посилання та реалізації у своїх власних програмах. Оскільки інтерфейс може використовуватися в Java-пакетах, які відрізняються від власних, публічна видимість забезпечує доступ коду програми до змінної.

2

Декларування внутрішніх підінтерфейсів є хорошою практикою, але ви не можете оголосити свої внутрішні методи як protected в інтерфейсі на Java, технічно.

Звичайно, ви можете створити інший інтерфейс для внутрішнього використання, який розширює загальнодоступний інтерфейс:

package yourpackage;

public interface PublicInterface {

    public void doThing1();

    public void doThing2();

    public void doThing3();

}

package yourpackage;

interface InternalInterface extends PublicInterface {

    void doAnyInternalThing1();

    void doAnyInternalThing2();

}

Ви можете використовувати InternalInterfaceінтерфейс всередині пакета, але вам слід прийняти будь-який підтип PublicInterface(у публічних методах):

package yourpackage;

public class SomeClass {

    public void someMethod(PublicInterface param) {
        if (param instanceof InternalInterface) {
            // run the optimized code
        } else {
            // run the general code
        }
    }

}

Поза пакетом користувачі можуть користуватися PublicInterfaceбез проблем.

Зазвичай програмісти створюють абстрактні класи в подібних ситуаціях. Однак у цьому випадку ми втрачаємо переваги багаторазового успадкування.


1
Поза пакетом користувачі також можуть використовувати YourPublicInterface.Internal. Все в інтерфейсі, включаючи вкладені інтерфейси, є загальнодоступними незалежно від наявності чи відсутності publicключового слова.
Грег Роелофс

1

Єдиний сценарій, коли це мало б сенс, коли ви хочете обмежити видимість тим самим пакетом. Всі інші види використання protectedне застосовуються. Зокрема, protectedметоди часто використовуються для надання доступу до деяких деталей реалізації нижчого рівня для нащадків. Але заявляти, що це в інтерфейсі, не має сенсу, оскільки не існує можливого впровадження нижчого рівня.

І навіть сценарій пакетів насправді не є тим, що стосується інтерфейсів.

Щоб досягти того, що ви, мабуть, хочете, вам потрібні два інтерфейси, один для внутрішнього використання та один, який ви виставляєте в загальнодоступному API. (З внутрішньою, можливо, але необов'язково поширюючи публічну.) Або, як зазначали інші, абстрактним суперкласом.


Абстрактний суперклас може запобігти виведенню типів поза його пакетом. Хтось, що отримує посилання такого типу суперкласу, хто довіряє автору пакету, може бути впевнений, що об’єкт буде вести себе як заявлено. Якщо в пакеті є кілька класів, які хочуть розкрити якусь загальну функціональність, але не відповідають правильній ієрархії (наприклад, одна реалізація функцій X і Y, одна Y і Z, і одна X і Z), було б корисно, якщо він може викрити функціональність, що використовує інтерфейси, хоча все ще обіцяє, що екземпляри, на які посилаються типи інтерфейсів, будуть "справжніми".
supercat

0

Захищені методи завжди доступні для підкласу, лише якщо підклас розширює базовий клас.

У випадку інтерфейсу підклас ніколи не поширює інтерфейс. Він реалізує інтерфейс.

Захищені методи доступні через розширення, а не з пристроєм .


яка різниця, яке ключове слово, не має значення.
Alex78191

0

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

public interface MyInterface {
    public void publicMethod(); // needs to be public
}

public abstract class MyAbstractClass implements MyInterface {
    @Override
    public void publicMethod() {
        protectedMethod(); // you can call protected method here
        // do other stuff
    }
    protected abstract void protectedMethod(); // can be protected
}

public class MyClass extends MyAbstractClass {
    @Override
    protected void protectedMethod() {
        // implement protected method here, without exposing it as public
    }
}

2
Але приватні методи, які ніхто не побачить, дозволені в інтерфейсах.
Alex78191

java має методи за замовчуванням в інтерфейсах, тобто інтерфейс є милицею, щоб обійти багатократне успадкування абстрактних класів. Нехай тоді допускається багатократне успадкування абстрактних класів. Конфлікти методів за замовчуванням не стали проблемою.
Alex78191

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

1
Ця відповідь просто ігнорує поставлене запитання: чому інтерфейси не можуть захищати методи? Захищені методи все ще "піддаватимуть методам зовнішній світ" , а твердження про те, що "ці методи є публічними за своєю природою" є просто хибним. Вони є загальнодоступними, оскільки мова була створена таким чином, але вона могла дозволити захищені методи в інтерфейсах. ОП просто запитує, чому.
skomisa
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.