Чому Java не дозволяє приватним членам інтерфейсу?


87

Чому Java не дозволяє приватним членам інтерфейсу? Чи є якась особлива причина?


@pst Я написав обхідний шлях у кінці своєї відповіді - stackoverflow.com/a/10169894/348975 . Чи це стосується ваших проблем?
emory

Java 9 надалі дозволено. Перевірте мій відповідь нижче: stackoverflow.com/questions/10169654 / ...
akhil_mittal

Відповіді:


87

З мовної специфікації Java (Контроль доступу) :

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

Контроль доступу полягає у приховуванні деталей реалізації. Інтерфейс не має реалізації, яку можна приховати.


9
Оскільки ми можемо розмістити класи вкладеності всередині інтерфейсу, ми можемо поставити реалізацію на інтерфейс. Робити це дуже неправильно, але ми можемо.
emory

29
Java 9 дозволяє приватні методи в інтерфейсі. Це логічно після додавання методів за замовчуванням, Посилання: bugs.openjdk.java.net/browse/JDK-8071453
Харіхаран,

3
"Робити це дуже неправильно" .. як завжди, залежить від контексту.
JacksOnF1re

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

48

У Java 9 можливі приватні методи в інтерфейсах.

Технічні характеристики Java 9

Команда компілятора javac рада повідомити про наявність підтримки компілятора для приватних методів в інтерфейсах, починаючи з 9 b54 збірки JDK.


10
@SebiSebi, момент, коли ти зрозумієш, що Java є живою мовою.
Arashsoft

@Arashsoft, OP запитує поля.
Pacerier

19

Методи приватного інтерфейсу є частиною Java 9 як частиною JEP-213 . Оскільки інтерфейси в Java 8 можуть мати методи за замовчуванням , приватні методи дозволяють декільком методам за замовчуванням використовувати спільний приватний метод.


13

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


Корисно знати про функції інтерфейсу Java-9.
Равіндра бабу

9

Інтерфейс використовується для опису API, який надається будь-яким класом, що реалізує інтерфейс. Оскільки інтерфейс з його визначення не має стану, в ньому не можна оголошувати членів поля.


У Java-країні учасником є ​​поле, метод, конструктор або клас.
emory

7

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

class OuterClass
{
     void run ( MyInterface x )
     {
           x . publicMethod ( ) ;  // why not?
           x . protectedMethod ( ) ; // why not?
           x . packagePrivateMethod ( ) ; // why not?
           x . privateMethod ( ) ; // why not?
     }

     interface MyInterface
     {
           public abstract void publicMethod ( ) ; // OK

           protected abstract void protectedMethod ( ) ; // why not?

           abstract void packagePrivateMethod ( ) ; // in interface default is public, but why not package private

           private void privateMethod ( ) ; // impossible to implement
     }

     class MyImpl implements MyInterface
     {
           public void publicMethod ( ) { } // ok

           protected void protectedMethod ( ) { } // no sweat

           void packagePrivateMethod ( ) { } // no sweat

           private void privateMethod ( ) { } // not happening
     }
}

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

class WorkAround
{
     void run ( MyPrivateInterface x )
     {
           x . publicMethod ( ) ;  
           x . protectedMethod ( ) ; 
           x . packagePrivateMethod ( ) ; 
           x . privateMethod ( ) ; 
     }

     public interface MyPublicInterface { void publicMethod ( ) ; }

     protected interface MyProtectedInterface extends MyPublicInterface { void protectedMethod ( ) ; }

     interface MyPackagePrivateInterface extends MyProtectedInterface { void packagePrivateMethod ( ) ; }

     private interface MyPrivateInterface extends MyPackagePrivateInterface { void privateMethod ( ) ; }
}

6

Відповідно до Javaмови програмування область застосування private membersобмежена тим, classв якій вона оголошена, і доступ до неї можливий лише за допомогою цих методів class. Але у intefaceнього немає тіла методу, отже, немає жодної можливості оголошувати приватних членів всередині interface.


4

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

public interface IData{
   default void processData(int data) {
      validate(data);
      // do some work with it
   }
   default void consumeData(int data) {
      validate(data);
      // do some work with it
   }
   private void validate(int data) {
     // validate data
   }
}

3

Це тому, що вони були б марними.

Не було б можливості викликати приватний метод.

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


Я не погоджуюсь з wrt "Не було б можливості викликати приватний метод". З внутрішніми класами міг би бути спосіб - stackoverflow.com/a/10169894/348975
emory

Розглянемо методи Java за замовчуванням 8. Інтерфейс I має методи за замовчуванням A і B з великою кількістю загального коду. Для рефакторингу цього вам потрібен метод C, який містив би лише спільний код і викликався A та B. У Java 8 це буде метод за замовчуванням, який піддається всім реалізаторам інтерфейсу. в Java 9 C міг бути приватним методом, видимим лише для методів за замовчуванням в межах І.
Іван Крилов,

2

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

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


Вибачте за копання могил тут :( Як у цьому випадку працює docs.oracle.com/javase/7/docs/api/java/io/Serializable.html ? Чи не можуть люди реалізувати це, а потім замінити методи readObject і writeObject ? Я впевнений, що мені чогось не вистачає
PatrickWalker

1

Приватні учасники не мають сенсу в інтерфейсі. Інтерфейс - це спосіб отримати доступ до класу з визначеними методами, де вам не потрібно бачити внутрішні елементи цього класу.

Приватні члени не погоджуються з цим.


0

Члени класу, які оголошені приватними, не успадковуються підкласами цього класу. Лише члени класу, які оголошені захищеними або загальнодоступними, успадковуються за підкласами, оголошеними в пакеті, відмінному від того, в якому оголошено клас.

Джерело

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


0

Так, не можу цього зробити. Для всіх, хто коментує, чому не слід:

Уявіть, у мене є клас A, який використовує інтерфейс I. Клас B поширює клас A, отже, також успадковує всі методи інтерфейсу в А.

Тепер, уявіть, я хочу приватний метод у класі A, але хочу, щоб він був визначений контрактом і для інших класів (можливо, класу C, який не обов’язково поширює клас B або A).

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

Єдиним рішенням є обхідний шлях, або просто примусовий метод init до самих класів без інтерфейсу.

Причину я розумію не надто точно, але все ж вона іноді може стати в нагоді. Очевидно, Oracle погоджується, оскільки вони дозволяють методи приватного інтерфейсу в JDK 9.

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

В іншому випадку вам доведеться спробувати інший обхідний шлях, якщо ви хочете, щоб внутрішня робота класу використовувала його .... можливо, сам метод встановлює прапор і вмикає, і використовує його. Коли прапор хибний, метод нічого не робить (це буде, коли хтось викликає його поза класом). Однак, коли власні методи класів викликають це, вони швидко встановлюють прапор на true, потім викликають метод, потім встановлюють прапор на false ??

Зрештою якийсь німий. Можливо, зараз просто краще просто розмістити приватний клас у самому класі та взагалі вирізати інтерфейс.

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