Dlaczego Java nie pozwala prywatnym członkom w interfejsie?

Odpowiedzi:

87

Ze specyfikacji języka Java (Kontrola dostępu) :

„Język programowania Java zapewnia mechanizmy kontroli dostępu, aby użytkownicy pakietu lub klasy nie byli uzależnieni od niepotrzebnych szczegółów implementacji tego pakietu lub klasy”.

Kontrola dostępu polega na ukrywaniu szczegółów implementacji. Interfejs nie ma implementacji do ukrycia.

Matten
źródło
9
Ponieważ możemy umieścić klasy zagnieżdżania wewnątrz interfejsu, możemy umieścić implementację w interfejsie. Takie postępowanie jest bardzo złe, ale możemy.
emory
29
Java 9 pozwala na prywatne metody w interfejsie, jest to logiczne po dodaniu domyślnych metod, Ref: bugs.openjdk.java.net/browse/JDK-8071453
Hariharan
3
„Takie postępowanie jest bardzo złe”… jak zawsze, zależy od kontekstu.
JacksOnF1re
5
Nie jest tak źle, jak się wydaje. Metody prywatne w interfejsie mogą być dostępne tylko domyślnie w tym samym interfejsie. Jedną z korzyści jest pomoc w rozbiciu implementacji metod domyślnych na znaczące mniejsze funkcje bez przerywania hermetyzacji.
Henry Pham
48

W Javie 9 możliwe są prywatne metody w interfejsach.

Specyfikacje Java 9

Zespół kompilatorów javac z przyjemnością informuje o dostępności obsługi kompilatorów dla metod prywatnych w interfejsach począwszy od wersji 9 b54 JDK.

chiperortiz
źródło
10
@SebiSebi, Moment, w którym zdajesz sobie sprawę, że Java jest żywym językiem.
Arashsoft
@Arashsoft, OP prosi o pola.
Pacerier
19

Prywatne metody interfejsu są częścią Java 9 jako część JEP-213 . Ponieważ interfejsy w Javie 8 mogą mieć metody domyślne, metody prywatne zezwalają na wiele domyślnych metod korzystania z udostępnionej metody prywatnej.

mkobit
źródło
13

Od wersji Java 8 interfejsy mogą mieć metody domyślne, a od wersji Java 9 interfejs może mieć metody prywatne, do których dostęp jest możliwy tylko przy użyciu metod domyślnych w tym samym interfejsie.

Peter Lawrey
źródło
Dobrze wiedzieć o funkcjach interfejsu Java-9.
Ravindra babu
9

Interfejs jest używany do opisu API, które jest dostarczane przez dowolną klasę implementującą interfejs. Ponieważ interfejs z definicji nie ma stanu, nie ma potrzeby deklarowania w nim elementów pola.

giorashc
źródło
W środowisku Java element członkowski jest polem, metodą, konstruktorem lub klasą.
emory
7

Nie byłoby sposobu na zaimplementowanie takiego interfejsu. Odpowiedź na zadane przeze mnie pytanie zdecydowanie sugeruje, że niemożliwe byłoby (bez radykalnej zmiany reguł) zaimplementowanie interfejsu z metodami prywatnymi - to pozostawia otwarte pytanie, dlaczego metody chronione i pakietowe nie są dozwolone.

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
     }
}

Poniższy kod powinien przynieść oczekiwany efekt. Chociaż wszystkie metody są publiczne, tylko metoda publiczna jest faktycznie publiczna. chroniona metoda jest skutecznie chroniona. packagePrivateMethod jest efektywnie packagePrivate. privateMethod jest faktycznie prywatny.

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 ( ) ; }
}
emory
źródło
6

Zgodnie z Javajęzykiem programowania zakres private membersjest ograniczony do tego, classw którym jest zadeklarowany i można uzyskać do niego dostęp tylko za pomocą metod class. Ale intefacenie ma treści metody, dlatego nie ma potrzeby deklarowania prywatnych członków wewnątrz pliku interface.

Nishant
źródło
4

Java zezwala na prywatne metody w interfejsie w Javie 9 . Te metody domyślne zostały wprowadzone w Javie 8. Możliwe jest, że wiele metod domyślne chcesz podzielić się jakiś kod, to kod ten może zostać przeniesiony do prywatnej metody bez narażania go do świata zewnętrznego. Ten błąd został naprawiony i począwszy od JDK 9 build 54, przywrócono obsługę kompilatorów dla prywatnych metod interfejsu.

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
   }
}
akhil_mittal
źródło
3

To dlatego, że byłyby bezużyteczne.

Nie byłoby sposobu na wywołanie metody prywatnej.

Prywatni członkowie są szczegółem implementacji. Interfejs dotyczy roli publicznej, którą może przyjąć klasa.

W W.
źródło
Nie zgadzam się, mówiąc: „Nie byłoby sposobu na wywołanie metody prywatnej”. Z klasami wewnętrznymi byłby sposób - stackoverflow.com/a/10169894/348975
emory
Rozważ domyślne metody java 8. Interfejs I ma domyślne metody A i B z dużą ilością wspólnego kodu. Aby to zmienić, potrzebowałbyś metody C, która zawierałaby tylko wspólny kod i byłaby wywoływana przez A i B. W Javie 8 byłaby to domyślna metoda, która jest widoczna dla wszystkich implementatorów interfejsu. w Javie 9 C może być metodą prywatną widoczną tylko dla metod domyślnych w ramach I.
Ivan Krylov
2

pola prywatne nie byłyby całkowicie bezużyteczne, ponieważ inne pola i klasy wewnętrzne miałyby do nich dostęp.

Jednak metody prywatne nie mogły zostać zaimplementowane, nawet w klasach zagnieżdżonych, co czyni je prawie bezużytecznymi. Możesz je przeczytać za pomocą odbicia, ale to raczej skrajny przypadek.

Peter Lawrey
źródło
Przepraszamy za kopanie grobów tutaj :( Jak docs.oracle.com/javase/7/docs/api/java/io/Serializable.html działa w tym przypadku? Czy ludzie nie mogą tego zaimplementować, a następnie nadpisać metody readObject i writeObject ? Jestem pewien, że czegoś mi brakuje
PatrickWalker
1

Prywatni członkowie nie mają sensu w interfejsie. Interfejs to sposób na dostęp do klasy ze zdefiniowanymi metodami, w którym nie musisz widzieć wnętrza tej klasy.

Prywatni członkowie się z tym nie zgadzają.

juergen d
źródło
0

Składowe klasy, które są zadeklarowane jako prywatne, nie są dziedziczone przez podklasy tej klasy. Tylko elementy członkowskie klasy, które są zadeklarowane jako chronione lub publiczne, są dziedziczone przez podklasy zadeklarowane w pakiecie innym niż ten, w którym klasa jest zadeklarowana.

Źródło

Więc nie masz żadnych metod pracy w interfejsie, które mogłyby pracować z tym prywatnym niedziedziczalnym polem, więc dlaczego miałoby ono istnieć?

Alireza Mohamadi
źródło
0

Tak, nie mogę tego zrobić. Dla wszystkich komentujących, dlaczego nie powinien:

Wyobraź sobie, że mam klasę A, która wykorzystuje interfejs I. Klasa B rozszerza klasę A, dlatego też dziedziczę wszystkie metody interfejsu w A.

Teraz wyobraź sobie, że chcę prywatną metodę w klasie A, ale chcę, aby była zdefiniowana w umowie również dla innych klas (może klasa C, która niekoniecznie rozszerza klasę B lub A).

Być może dla metody „inicjalizacji”, której chcę dla wszystkich klas używających interfejsu I. Ale oczywiście nie chcę, aby metoda inicjalizacji była publiczna ... ponieważ powinna być używana tylko raz, lub jeśli klasa uzna to za konieczne, a nie tylko dlatego, że chcesz użyć jej wszystkich chcąc nie chcąc.

Jedynym rozwiązaniem jest obejście problemu lub po prostu wymuszenie metody init w samych klasach bez interfejsu.

Na pewno nie rozumiem tego powodu, ale czasami może się przydać. Wyraźnie Oracle zgadza się, ponieważ zezwala na prywatne metody interfejsu w JDK 9.

To, co zrobiłem, w każdym razie dla mojego, to umieszczenie prostej zmiennej boolowskiej, w ten sposób metoda interfejsu (która powinna być prywatna) może zostać oznaczona jako prawda (zainicjowana = prawda) po jednorazowym ustawieniu. Po ponownym wywołaniu metoda po prostu nic nie robi. W ten sposób metoda interfejsu może zostać zaimplementowana jako publiczna, ale ponieważ konstruktor (mojej klasy) najpierw wywołuje metodę, ustawia to zmienną na true, więc nie można jej ponownie wywołać.

W przeciwnym razie musiałbyś wypróbować inne obejście, jeśli chcesz, aby tylko wewnętrzne funkcje klasy używały jej ... być może sama metoda ustawia flagę, gdy jej używa. Gdy flaga ma wartość false, metoda nic nie robi (byłoby tak, gdy ktoś wywoła ją spoza klasy). Jednak gdy wywołują ją metody klasy, szybko ustawiają flagę na wartość true, następnie wywołują metodę, a następnie ustawiają flagę na wartość false ??

W końcu coś w rodzaju wyciszenia. Prawdopodobnie na razie lepiej po prostu umieścić klasę prywatną w samej klasie i całkowicie odciąć interfejs.

Archanioł Tyrael
źródło