Zauważyłem, że klasy zewnętrzne mogą uzyskać dostęp do prywatnych zmiennych instancji klas wewnętrznych. Jak to jest możliwe? Oto przykładowy kod demonstrujący to samo:
class ABC{
class XYZ{
private int x=10;
}
public static void main(String... args){
ABC.XYZ xx = new ABC().new XYZ();
System.out.println("Hello :: "+xx.x); ///Why is this allowed??
}
}
Dlaczego takie zachowanie jest dozwolone?
new ABC().new XYZ()
Odpowiedzi:
Klasa wewnętrzna jest po prostu sposobem na czyste oddzielenie niektórych funkcji, które naprawdę należą do oryginalnej klasy zewnętrznej. Są przeznaczone do użycia, gdy masz 2 wymagania:
Biorąc pod uwagę te wymagania, klasy wewnętrzne mają pełny dostęp do swojej klasy zewnętrznej. Ponieważ są w zasadzie członkami klasy zewnętrznej, ma sens, że mają dostęp do metod i atrybutów klasy zewnętrznej - w tym szeregowych.
źródło
Jeśli chcesz ukryć prywatnych członków swojej klasy wewnętrznej, możesz zdefiniować interfejs z członkami publicznymi i utworzyć anonimową klasę wewnętrzną, która implementuje ten interfejs. Przykład poniżej:
źródło
x
jest tutaj publiczny, nie jest dozwolony jakmMember.x
.Klasa wewnętrzna jest (do celów kontroli dostępu) uważana za część klasy zawierającej. Oznacza to pełny dostęp do wszystkich szeregowych.
Sposób implementacji polega na użyciu syntetycznych metod chronionych przez pakiet: klasa wewnętrzna zostanie skompilowana do oddzielnej klasy w tym samym pakiecie (ABC $ XYZ). JVM nie obsługuje bezpośrednio tego poziomu izolacji, więc na poziomie kodu bajtowego ABC $ XYZ będzie mieć metody chronione pakietem, których klasa zewnętrzna używa do uzyskiwania dostępu do prywatnych metod / pól.
źródło
Pojawia się poprawna odpowiedź na inne pytanie podobne do tego: Dlaczego można uzyskać dostęp do prywatnego elementu członkowskiego zagnieżdżonej klasy za pomocą metod klasy otaczającej?
Mówi się, że w JLS istnieje definicja prywatnego zakresu - Określanie dostępności :
źródło
Ważnym przypadkiem użycia IMHO dla klas wewnętrznych jest wzorzec fabryki. Klasa otaczająca może przygotować instancję klasy wewnętrznej bez ograniczeń dostępu i przekazać instancję do świata zewnętrznego, gdzie prywatny dostęp będzie honorowany.
W przeciwieństwie do abyx deklarowanie statycznej klasy nie zmienia ograniczeń dostępu do klasy otaczającej, jak pokazano poniżej. Działają również ograniczenia dostępu między klasami statycznymi w tej samej klasie otaczającej. Byłem zaskoczony ...
źródło
Ograniczenia dostępu są ustalane dla poszczególnych klas. Nie ma możliwości, aby metoda zadeklarowana w klasie nie mogła uzyskać dostępu do wszystkich elementów członkowskich instancji / klasy. Z tego wynika, że klasy wewnętrzne również mają nieograniczony dostęp do członków klasy zewnętrznej, a klasa zewnętrzna ma nieograniczony dostęp do członków klasy wewnętrznej.
Umieszczając klasę w innej klasie, sprawiasz, że jest ona ściśle powiązana z implementacją, a wszystko, co jest częścią implementacji, powinno mieć dostęp do innych części.
źródło
Logika stojąca za klasami wewnętrznymi jest taka, że jeśli tworzysz klasę wewnętrzną w klasie zewnętrznej, dzieje się tak dlatego, że będą one musiały udostępniać kilka rzeczy, a zatem ma sens, aby mogły mieć większą elastyczność niż „zwykłe” klasy.
Jeśli w twoim przypadku nie ma sensu, aby klasy mogły widzieć swoje wewnętrzne działanie - co zasadniczo oznacza, że klasa wewnętrzna mogła po prostu zostać utworzona jako zwykła klasa, możesz zadeklarować klasę wewnętrzną jako
static class XYZ
. Używaniestatic
będzie oznaczać, że nie będą dzielić stanu (i na przykładnew ABC().new XYZ()
nie będą działać, a będziesz musiał użyćnew ABC.XYZ()
.Ale jeśli tak jest, powinieneś pomyśleć o tym, czy
XYZ
naprawdę powinna być klasą wewnętrzną i może zasługuje na swoją własną) Czasami sensowne jest utworzenie statycznej klasy wewnętrznej (na przykład, jeśli potrzebujesz małej klasy, która implementuje interfejs, z którego korzysta Twoja klasa zewnętrzna, i nie będzie to pomocne nigdzie indziej). Ale mniej więcej w połowie przypadków powinien był być klasą zewnętrzną.źródło
Thilo dodał dobrą odpowiedź na Twoje pierwsze pytanie „Jak to możliwe?”. Chciałbym nieco rozwinąć drugie zadane pytanie: Dlaczego takie zachowanie jest dozwolone?
Na początek wyjaśnijmy, że to zachowanie nie ogranicza się do klas wewnętrznych, które z definicji są niestatycznymi typami zagnieżdżonymi. To zachowanie jest dozwolone dla wszystkich typów zagnieżdżonych, w tym zagnieżdżonych wyliczeń i interfejsów, które muszą być statyczne i nie mogą mieć obejmującego wystąpienia. Zasadniczo model jest uproszczeniem do następującej instrukcji: Zagnieżdżony kod ma pełny dostęp do otaczającego kodu - i odwrotnie.
Więc dlaczego? Myślę, że przykład lepiej to ilustruje.
Pomyśl o swoim ciele i mózgu. Jeśli wstrzykniesz heroinę w ramię, twój mózg się rozpali. Jeśli obszar ciała migdałowatego twojego mózgu zobaczy, co według niego stanowi zagrożenie dla twojego osobistego bezpieczeństwa, na przykład osa, sprawi, że twoje ciało obróci się w drugą stronę i pobiegnie w kierunku wzgórz bez Ciebie „zastanawiasz się” dwa razy o tym.
Mózg jest więc nieodłączną częścią ciała - i, co dziwne, także na odwrót. Korzystanie z kontroli dostępu między tak blisko powiązanymi podmiotami powoduje utratę praw do związku. Jeśli potrzebujesz kontroli dostępu, musisz bardziej rozdzielić klasy na naprawdę odrębne jednostki. Do tego czasu są tą samą jednostką. Dobrym przykładem dla dalszych badań byłoby przyjrzenie się, jak
Iterator
zwykle implementowana jest Java .Nieograniczony dostęp od kodu zamykającego do kodu zagnieżdżonego sprawia, że w większości przypadków dodawanie modyfikatorów dostępu do pól i metod typu zagnieżdżonego jest raczej bezużyteczne. Takie postępowanie dodaje bałaganu i może zapewnić fałszywe poczucie bezpieczeństwa dla nowych użytkowników języka programowania Java.
źródło
Klasa wewnętrzna jest traktowana jako atrybut klasy Outer. Dlatego niezależnie od tego, czy zmienna instancji klasy Inner jest prywatna, czy nie, klasa Outer może uzyskać do niej dostęp bez żadnego problemu, tak jak dostęp do jej innych atrybutów prywatnych (zmiennych).
źródło
Ponieważ twoja
main()
metoda znajduje się wABC
klasie, która może uzyskać dostęp do własnej klasy wewnętrznej.źródło
ABC
klasy mają dostęp do klas zagnieżdżonych wABC
klasie, ale dlaczego mają dostęp do prywatnych członków klas zagnieżdżonych wABC
klasie w Javie.