Klasa wewnętrzna Java i klasa zagnieżdżona statycznie

1765

Jaka jest główna różnica między klasą wewnętrzną a statyczną klasą zagnieżdżoną w Javie? Czy projekt / wdrożenie odgrywa rolę w wyborze jednego z nich?

Wszechmocny
źródło
65
Odpowiedź Joshuy Blocha brzmi: „ Skuteczne czytanie w Javie”item 22 : Favor static member classes over non static
Raymond Chenon
4
Dla przypomnienia, jest to pozycja 24 w 3. wydaniu tej samej książki.
ZeroCool,

Odpowiedzi:

1696

Z samouczka Java :

Klasy zagnieżdżone są podzielone na dwie kategorie: statyczne i niestatyczne. Klasy zagnieżdżone, które są zadeklarowane jako statyczne, są po prostu nazywane statycznymi klasami zagnieżdżonymi. Niestatyczne klasy zagnieżdżone nazywane są klasami wewnętrznymi.

Dostęp do klas zagnieżdżonych statycznie można uzyskać za pomocą otaczającej nazwy klasy:

OuterClass.StaticNestedClass

Na przykład, aby utworzyć obiekt dla statycznej klasy zagnieżdżonej, użyj następującej składni:

OuterClass.StaticNestedClass nestedObject = new OuterClass.StaticNestedClass();

Obiekty będące instancjami klasy wewnętrznej istnieją w instancji klasy zewnętrznej. Rozważ następujące klasy:

class OuterClass {
    ...
    class InnerClass {
        ...
    }
}

Instancja InnerClass może istnieć tylko w ramach instancji OuterClass i ma bezpośredni dostęp do metod i pól swojej instancji.

Aby utworzyć instancję klasy wewnętrznej, musisz najpierw utworzyć instancję klasy zewnętrznej. Następnie utwórz wewnętrzny obiekt w obrębie zewnętrznego obiektu za pomocą następującej składni:

OuterClass outerObject = new OuterClass()
OuterClass.InnerClass innerObject = outerObject.new InnerClass();

patrz: Tutorial Java - zagnieżdżone klasy

Dla kompletności należy zauważyć, że istnieje również coś takiego jak klasa wewnętrzna bez otaczającej instancji :

class A {
  int t() { return 1; }
  static A a =  new A() { int t() { return 2; } };
}

Tutaj new A() { ... }jest klasą wewnętrzną zdefiniowaną w kontekście statycznym i nie ma otaczającej instancji.

Jaskółka oknówka
źródło
130
Pamiętaj, że możesz również zaimportować bezpośrednio statyczną klasę zagnieżdżoną, tzn. Możesz to zrobić (na górze pliku): import OuterClass.StaticNestedClass; następnie odwołaj się do klasy tak jak OuterClass.
Camilo Díaz Repka
4
@Martin, czy istnieje jakaś konkretna nazwa techniczna tego idiomu tworzenia wewnętrznej klasy OuterClass.InnerClass innerObject = outerObject.new InnerClass();?
Geek
7
Jaki jest więc pożytek z prywatnej statycznej klasy zagnieżdżonej? Myślę, że nie możemy utworzyć go z zewnątrz, jak OuterClass.StaticNestedClass nestedObject = new OuterClass.StaticNestedClass ();
RoboAlex,
1
@Ilya Kogan: Miałem na myśli, że wiem, że możemy uzyskać dostęp do pól klasy rodzica statycznych lub niestatycznych (jeśli klasa potomna jest klasą niestatyczną) kilka razy korzystałem z ich funkcji, ale zastanawiałem się, jaki to model pamięci oni podążają? czy koncepcje OOP obejmują je jako odrębną koncepcję? jeśli nie tam, gdzie naprawdę pasują do OOP. Wydaje mi się klasą przyjaciół :)
Mubashar
4
@martin, wiem, że przychodzę do tego wątku niezwykle późno, ale: to twoja zmienna, a, to jest pole statyczne klasy, A. To nie oznacza anonimowej klasy utworzonej przez 'new A () {int t () {return 2; }} jest statyczny tak samo, jak gdybym po prostu przypisał dowolny inny obiekt do pola statycznego, a, jak w: class B {static void main (string s) {Aa = new A ()}} (A i B to samo pakiet) To nie czyni klasy A statyczną. Wyrażenie „kontekst statyczny” w odnośniku cytowanym w wątku, z którym się łączysz, jest niezwykle niejasne. W rzeczywistości odnotowano to w wielu komentarzach w tym wątku.
GrantRobertson
599

Samouczek Java mówi :

Terminologia: Zagnieżdżone klasy są podzielone na dwie kategorie: statyczne i niestatyczne. Klasy zagnieżdżone, które są zadeklarowane jako statyczne, są po prostu nazywane statycznymi klasami zagnieżdżonymi. Niestatyczne klasy zagnieżdżone nazywane są klasami wewnętrznymi.

W języku potocznym terminy „zagnieżdżone” i „wewnętrzne” są używane zamiennie przez większość programistów, ale użyję poprawnego terminu „klasa zagnieżdżona”, która obejmuje zarówno wewnętrzne, jak i statyczne.

Klasy mogą być zagnieżdżane w nieskończoność , np. Klasa A może zawierać klasę B, która zawiera klasę C, która zawiera klasę D itp. Jednak więcej niż jeden poziom zagnieżdżania klas jest rzadki, ponieważ jest to ogólnie zły projekt.

Istnieją trzy powody, dla których możesz utworzyć zagnieżdżoną klasę:

  • organizacja: czasami najbardziej sensowne wydaje się posortowanie klasy do przestrzeni nazw innej klasy, szczególnie gdy nie będzie ona używana w żadnym innym kontekście
  • dostęp: klasy zagnieżdżone mają specjalny dostęp do zmiennych / pól zawartych w nich klas (dokładnie, które zmienne / pola zależą od rodzaju klasy zagnieżdżonej, wewnętrznej lub statycznej).
  • wygoda: konieczność utworzenia nowego pliku dla każdego nowego typu jest uciążliwa, szczególnie gdy typ będzie używany tylko w jednym kontekście

Istnieją cztery rodzaje zagnieżdżonych klas w Javie . W skrócie są to:

  • klasa statyczna : zadeklarowana jako element statyczny innej klasy
  • klasa wewnętrzna : zadeklarowana jako członek instancji innej klasy
  • lokalna klasa wewnętrzna : zadeklarowana w metodzie instancji innej klasy
  • anonimowa klasa wewnętrzna : jak lokalna klasa wewnętrzna, ale napisana jako wyrażenie zwracające jednorazowy obiekt

Pozwól mi rozwinąć bardziej szczegółowo.


Klasy statyczne

Klasy statyczne są najłatwiejsze do zrozumienia, ponieważ nie mają nic wspólnego z instancjami zawierającej klasy.

Klasa statyczna to klasa zadeklarowana jako element statyczny innej klasy. Podobnie jak inne elementy statyczne, taka klasa jest tak naprawdę tylko wieszakiem, który używa zawierającej klasy jako przestrzeni nazw, np . Klasa Koza zadeklarowana jako element statyczny klasy Rhino w pakiecie pizza jest znana pod nazwą pizza.Rhino.Goat .

package pizza;

public class Rhino {

    ...

    public static class Goat {
        ...
    }
}

Szczerze mówiąc, klasy statyczne są dość bezwartościową funkcją, ponieważ klasy są już podzielone na przestrzenie nazw według pakietów. Jedynym realnym możliwym powodem do stworzenia klasy statycznej jest to, że taka klasa ma dostęp do prywatnych elementów statycznych zawierającej klasę, ale uważam, że jest to dość kiepskie uzasadnienie istnienia funkcji klasy statycznej.


Klasy wewnętrzne

Klasa wewnętrzna to klasa zadeklarowana jako element niestatyczny innej klasy:

package pizza;

public class Rhino {

    public class Goat {
        ...
    }

    private void jerry() {
        Goat g = new Goat();
    }
}

Podobnie jak w przypadku klasy statycznej, klasa wewnętrzna jest znana jako kwalifikowana na podstawie nazwy klasy zawierającej, pizza.Rhino.Goat , ale wewnątrz klasy zawierającej może być znana pod nazwą prostą. Jednak każde wystąpienie klasy wewnętrznej jest powiązane z konkretnym wystąpieniem klasy zawierającej: powyżej, Koza stworzona w jerry , jest domyślnie powiązana z instancją Rhino w tej jerry . W przeciwnym razie jawne skojarzenie instancji Rhino jest jawne, gdy tworzymy instancję Koza :

Rhino rhino = new Rhino();
Rhino.Goat goat = rhino.new Goat();

(Zauważ, że określasz wewnętrzny typ jako „ Koza” w dziwnej nowej składni: Java wyprowadza typ zawierający z części nosorożca . I tak, nowa rhino.Goat () też miałby dla mnie większy sens).

Co nas to zyskuje? Cóż, instancja klasy wewnętrznej ma dostęp do elementów instancji zawierającej instancję klasy. O tych członkach obejmujących instancję odwołuje się wewnątrz klasy wewnętrznej tylko poprzez ich proste nazwy, a nie przez to ( to w klasie wewnętrznej odnosi się do instancji klasy wewnętrznej, a nie powiązanej zawierającej instancji klasy):

public class Rhino {

    private String barry;

    public class Goat {
        public void colin() {
            System.out.println(barry);
        }
    }
}

W wewnętrznej klasy, można odwołać się do tego od zawierającego klasy jako Rhino.this , i można użyć tego , aby odnieść się do swoich członków, np Rhino.this.barry .


Lokalne klasy wewnętrzne

Lokalna klasa wewnętrzna to klasa zadeklarowana w treści metody. Taka klasa jest znana tylko w ramach jej metody zawierającej, więc można ją tworzyć tylko i tworzyć do niej elementy. Korzyścią jest to, że lokalna instancja klasy wewnętrznej jest powiązana i może uzyskiwać dostęp do końcowych zmiennych lokalnych swojej metody zawierającej. Gdy instancja korzysta z ostatecznego ustawienia lokalnego swojej metody zawierającej, zmienna zachowuje wartość, którą trzymała w momencie jej tworzenia, nawet jeśli zmienna wykroczyła poza zakres (jest to w rzeczywistości surowa, ograniczona wersja zamknięć Javy).

Ponieważ lokalna klasa wewnętrzna nie jest członkiem klasy ani pakietu, nie jest zadeklarowana z poziomem dostępu. (Wyjaśnij jednak, że jego członkowie mają poziomy dostępu jak w normalnej klasie).

Jeśli lokalna klasa wewnętrzna jest zadeklarowana w metodzie instancji, tworzenie instancji klasy wewnętrznej jest powiązane z instancją utrzymywaną przez metodę zawierającą to w momencie tworzenia instancji, a zatem elementy instancji klasy zawierającej są dostępne tak jak w instancji klasa wewnętrzna. Lokalna klasa wewnętrzna jest tworzona po prostu poprzez jej nazwę, np. Lokalna klasa wewnętrzna Cat jest tworzona jako nowa Cat () , a nie nowa this.Cat (), jak można się spodziewać.


Anonimowe klasy wewnętrzne

Anonimowa klasa wewnętrzna to wygodny pod względem składni sposób pisania lokalnej klasy wewnętrznej. Najczęściej lokalna klasa wewnętrzna jest tworzona najwyżej tylko raz za każdym razem, gdy uruchamiana jest jej metoda zawierająca. Byłoby więc miło, gdybyśmy mogli połączyć definicję lokalnej klasy wewnętrznej i jej pojedynczą instancję w jedną wygodną formę składni, a także byłoby miło, gdybyśmy nie musieli wymyślać nazwy klasy (im mniej pomocna imiona zawierają Twój kod, tym lepiej). Anonimowa klasa wewnętrzna pozwala na obie te rzeczy:

new *ParentClassName*(*constructorArgs*) {*members*}

Jest to wyrażenie zwracające nowe wystąpienie nienazwanej klasy, które rozszerza ParentClassName . Nie możesz dostarczyć własnego konstruktora; dostarczany jest domyślnie jeden, który po prostu wywołuje superkonstruktor, więc podane argumenty muszą pasować do superkonstruktora. (Jeśli rodzic zawiera wiele konstruktorów, ten „najprostszy” nazywa się „najprostszym”, co wynika z dość złożonego zestawu zasad, których nie warto zawracać głowy szczegółową nauką - wystarczy zwrócić uwagę na to, co mówią NetBeans lub Eclipse.)

Alternatywnie możesz określić interfejs do wdrożenia:

new *InterfaceName*() {*members*}

Taka deklaracja tworzy nową instancję nienazwanej klasy, która rozszerza Object i implementuje InterfaceName . Ponownie nie możesz dostarczyć własnego konstruktora; w tym przypadku Java domyślnie dostarcza konstruktora no-arg, nic nie rób (więc w tym przypadku nigdy nie będzie argumentów konstruktora).

Chociaż nie możesz nadać anonimowemu konstruktorowi klasy wewnętrznej, nadal możesz wykonać dowolną konfigurację, używając bloku inicjalizującego (blok {} umieszczony poza jakąkolwiek metodą).

Wyjaśnij, że anonimowa klasa wewnętrzna jest po prostu mniej elastycznym sposobem tworzenia lokalnej klasy wewnętrznej za pomocą jednej instancji. Jeśli chcesz lokalną klasę wewnętrzną, która implementuje wiele interfejsów lub która implementuje interfejsy, jednocześnie rozszerzając klasę inną niż Object lub która określa własnego konstruktora, utkniesz tworząc regularną lokalną klasę wewnętrzną.

Jegschemesch
źródło
39
Świetna historia, dzięki. Ma jednak jeden błąd. Możesz uzyskać dostęp do pól klasy zewnętrznej z klasy wewnętrznej instancji przez Rhino.this.variableName.
Thirler
2
Chociaż nie możesz zapewnić własnego konstruktora dla anonimowych klas wewnętrznych, możesz użyć inicjalizacji podwójnego nawiasu klamrowego. c2.com/cgi/wiki?DoubleBraceInitialization
Casebash
30
Świetne wytłumaczenie, ale nie zgadzam się z tym, że statyczne klasy wewnętrzne są bezwartościowe. Zobacz rwhansen.blogspot.com/2007/07/..., aby zobaczyć wielką odmianę wzorca konstruktora, który w dużym stopniu zależy od użycia statycznych klas wewnętrznych.
Mansoor Siddiqui
9
Nie zgadzam się również z tym, że statyczna klasa wewnętrzna jest bezwartościowa: jeśli chcesz wyliczenia w klasie wewnętrznej, musisz uczynić klasę wewnętrzną statyczną.
Ktoś gdzieś
9
Prywatne statyczne zagnieżdżone klasy są również bardzo przydatne: chcesz je mieć, ale nie chcesz ich ujawniać. Jak wpis <T> na LinkedList <T> lub AsyncTasks wewnątrz działania (Android) itp.
Lorenzo Dematté
150

Nie sądzę, aby prawdziwa różnica stała się jasna w powyższych odpowiedziach.

Najpierw popraw warunki:

  • Klasa zagnieżdżona to klasa zawarta w innej klasie na poziomie kodu źródłowego.
  • Jest statyczny, jeśli zadeklarujesz go za pomocą modyfikatora statycznego .
  • Niestatyczna klasa zagnieżdżona nazywa się klasą wewnętrzną. (Pozostaję przy niestatycznej klasie zagnieżdżonej).

Jak dotąd odpowiedź Martina jest słuszna. Jednak faktyczne pytanie brzmi: jaki jest cel deklarowania statycznej klasy zagnieżdżonej, czy nie?

Używasz statycznych klas zagnieżdżonych, jeśli chcesz utrzymać klasy razem, jeśli należą one do siebie lokalnie lub jeśli klasa zagnieżdżona jest używana wyłącznie w klasie zamykającej. Nie ma semantycznej różnicy między statyczną klasą zagnieżdżoną a każdą inną klasą.

Niestatyczne klasy zagnieżdżone to inna bestia. Podobne do anonimowych klas wewnętrznych, takie zagnieżdżone klasy są w rzeczywistości zamknięciami. Oznacza to, że przechwytują otaczający ich zakres i otaczającą go instancję i udostępniają ją. Być może jakiś przykład to wyjaśni. Zobacz ten skrót kontenera:

public class Container {
    public class Item{
        Object data;
        public Container getContainer(){
            return Container.this;
        }
        public Item(Object data) {
            super();
            this.data = data;
        }

    }

    public static Item create(Object data){
        // does not compile since no instance of Container is available
        return new Item(data);
    }
    public Item createSubItem(Object data){
        // compiles, since 'this' Container is available
        return new Item(data);
    }
}

W takim przypadku chcesz mieć odniesienie z elementu podrzędnego do kontenera nadrzędnego. Korzystanie z niestatycznej klasy zagnieżdżonej działa bezproblemowo. Możesz uzyskać dostęp do zamykającej instancji kontenera za pomocą składni Container.this.

Bardziej ostre wyjaśnienia:

Jeśli spojrzysz na bajtowe kody Java, kompilator generuje (niestatyczną) klasę zagnieżdżoną, może stać się jeszcze jaśniejszy:

// class version 49.0 (49)
// access flags 33
public class Container$Item {

  // compiled from: Container.java
  // access flags 1
  public INNERCLASS Container$Item Container Item

  // access flags 0
  Object data

  // access flags 4112
  final Container this$0

  // access flags 1
  public getContainer() : Container
   L0
    LINENUMBER 7 L0
    ALOAD 0: this
    GETFIELD Container$Item.this$0 : Container
    ARETURN
   L1
    LOCALVARIABLE this Container$Item L0 L1 0
    MAXSTACK = 1
    MAXLOCALS = 1

  // access flags 1
  public <init>(Container,Object) : void
   L0
    LINENUMBER 12 L0
    ALOAD 0: this
    ALOAD 1
    PUTFIELD Container$Item.this$0 : Container
   L1
    LINENUMBER 10 L1
    ALOAD 0: this
    INVOKESPECIAL Object.<init>() : void
   L2
    LINENUMBER 11 L2
    ALOAD 0: this
    ALOAD 2: data
    PUTFIELD Container$Item.data : Object
    RETURN
   L3
    LOCALVARIABLE this Container$Item L0 L3 0
    LOCALVARIABLE data Object L0 L3 2
    MAXSTACK = 2
    MAXLOCALS = 3
}

Jak widać, kompilator tworzy ukryte pole Container this$0. Jest to ustawiane w konstruktorze, który ma dodatkowy parametr typu Kontener, aby określić dołączającą instancję. Nie możesz zobaczyć tego parametru w źródle, ale kompilator domyślnie generuje go dla zagnieżdżonej klasy.

Przykład Martina

OuterClass.InnerClass innerObject = outerObject.new InnerClass();

byłby więc skompilowany do wywołania czegoś podobnego (w kodach bajtowych)

new InnerClass(outerObject)

Ze względu na kompletność:

Anonimowa klasa jest doskonałym przykładem niestatycznej zagnieżdżonej klasy, która po prostu nie ma z nią żadnej nazwy i nie można do niej odwoływać się później.

jrudolph
źródło
17
„Nie ma semantycznej różnicy między statyczną klasą zagnieżdżoną a każdą inną klasą”. Z wyjątkiem tego, że klasa zagnieżdżona może zobaczyć prywatne pola / metody rodzica, a klasa nadrzędna może zobaczyć prywatne pola / metody zagnieżdżone.
Brad Cupit
Czy niestatyczna klasa wewnętrzna nie spowodowałaby masywnych wycieków pamięci? Jak za każdym razem, gdy tworzysz słuchacza, tworzysz przeciek?
G_V,
3
@G_V zdecydowanie istnieje potencjał wycieków pamięci, ponieważ instancja klasy wewnętrznej zachowuje odniesienie do klasy zewnętrznej. To, czy jest to rzeczywisty problem, zależy od tego, gdzie i jak przechowywane są odwołania do instancji klas zewnętrznych i wewnętrznych.
jrudolph,
94

Myślę, że żadna z powyższych odpowiedzi nie wyjaśnia prawdziwej różnicy między klasą zagnieżdżoną a statyczną klasą zagnieżdżoną pod względem projektowania aplikacji:

Przegląd

Zagnieżdżona klasa może być niestatyczna lub statyczna iw każdym przypadku jest klasą zdefiniowaną w innej klasie . Klasa zagnieżdżona powinna istnieć tylko po to, aby służyć była klasą zamykającą , jeśli klasa zagnieżdżona jest przydatna dla innych klas (nie tylko obejmującej), powinna zostać zadeklarowana jako klasa najwyższego poziomu.

Różnica

Niestatyczna klasa zagnieżdżona : jest domyślnie powiązana z otaczającą instancją klasy zawierającej, co oznacza, że ​​możliwe jest wywoływanie metod i zmiennych dostępu do zamykającej instancji. Jednym z powszechnych zastosowań niestatycznej klasy zagnieżdżonej jest zdefiniowanie klasy adaptera.

Statyczna klasa zagnieżdżona : nie może uzyskać dostępu do instancji klasy otaczającej i wywołać na niej metody, dlatego należy jej użyć, gdy klasa zagnieżdżona nie wymaga dostępu do instancji klasy zamykającej. Częstym zastosowaniem statycznej klasy zagnieżdżonej jest implementacja komponentów obiektu zewnętrznego.

Wniosek

Główną różnicą między nimi z punktu widzenia projektu jest: niestatyczna klasa zagnieżdżona może uzyskać dostęp do wystąpienia klasy kontenera, podczas gdy statyczna nie .

Aleroot
źródło
: z twojego wniosku „podczas gdy statyczny nie może”, nawet statycznych wystąpień kontenera? Pewnie?
VdeX,
Częstym zastosowaniem statycznej klasy zagnieżdżonej jest wzorzec projektu ViewHolder w RecyclerView i ListView.
Hamzeh Soboh
1
W wielu przypadkach krótka odpowiedź jest wyraźniejsza i lepsza. To jest taki przykład.
Eric Wang,
32

Mówiąc prościej, potrzebujemy klas zagnieżdżonych przede wszystkim dlatego, że Java nie zapewnia zamknięć.

Klasy zagnieżdżone to klasy zdefiniowane w treści innej klasy zamykającej. Są dwojakiego rodzaju - statyczne i niestatyczne.

Są one traktowane jako członkowie klasy zamykającej, dlatego można określić dowolny z czterech specyfikatorów dostępu - private, package, protected, public. Nie mamy tego luksusu z klasami na najwyższym poziomie, które mogą być zadeklarowane publiclub prywatne.

Klasy wewnętrzne zwane także klasami bez stosu mają dostęp do innych członków najwyższej klasy, nawet jeśli są zadeklarowane jako prywatne, podczas gdy statyczne klasy zagnieżdżone nie mają dostępu do innych członków najwyższej klasy.

public class OuterClass {
    public static class Inner1 {
    }
    public class Inner2 {
    }
}

Inner1jest naszą statyczną klasą wewnętrzną i Inner2jest naszą klasą wewnętrzną, która nie jest statyczna. Kluczową różnicą między nimi jest to, że nie można utworzyć Inner2instancji bez Outera, ponieważ można utworzyć Inner1obiekt niezależnie.

Kiedy używałbyś klasy wewnętrznej?

Pomyśl o sytuacji, w której Class Ai Class Bsą powiązane, Class Bmuszą uzyskać dostęp do Class Aczłonków i Class Bsą powiązane tylko z Class A. Klasy wewnętrzne pojawiają się na zdjęciu.

Aby utworzyć instancję klasy wewnętrznej, musisz utworzyć instancję klasy zewnętrznej.

OuterClass outer = new OuterClass();
OuterClass.Inner2 inner = outer.new Inner2();

lub

OuterClass.Inner2 inner = new OuterClass().new Inner2();

Kiedy użyjesz statycznej klasy wewnętrznej?

Zdefiniowałbyś statyczną klasę wewnętrzną, gdy wiesz, że nie ma ona żadnego związku z wystąpieniem otaczającej klasy / najwyższej klasy. Jeśli twoja klasa wewnętrzna nie używa metod ani pól klasy zewnętrznej, to tylko marnowanie miejsca, więc zrób to statycznie.

Na przykład, aby utworzyć obiekt dla statycznej klasy zagnieżdżonej, użyj następującej składni:

OuterClass.Inner1 nestedObject = new OuterClass.Inner1();

Zaletą statycznej klasy zagnieżdżonej jest to, że nie potrzebuje do działania obiektu zawierającego klasę / najwyższą klasę. Może to pomóc w zmniejszeniu liczby obiektów tworzonych przez aplikację w czasie wykonywania.

Thalaivar
źródło
3
miałeś na myśli OuterClass.Inner2 inner = outer.new Inner2();?
Erik Kaplun,
4
static innerjest sprzecznością pod względem.
user207421
A klasy wewnętrzne nie są również znane jako „klasy bez stosu”. Nie używaj formatowania kodu dla tekstu, który nie jest kodem, i używaj go do tekstu, który jest.
user207421
30

Oto kluczowe różnice i podobieństwa między wewnętrzną klasą Java a statyczną klasą zagnieżdżoną.

Mam nadzieję, że to pomoże!

Klasa wewnętrzna

  • Może uzyskać dostęp do zewnętrznych klas zarówno metod instancji, jak i metod i pól
  • Powiązany z instancją klasy otaczającej, więc aby utworzyć jej instancję, najpierw potrzebna jest instancja klasy zewnętrznej (zwróć uwagę na nowe słowo kluczowe miejsce):

    Outerclass.InnerClass innerObject = outerObject.new Innerclass();
  • Nie można określić wszelkie elementy statyczne sama

  • Nie może mieć deklaracji klasy lub interfejsu

Statycznie zagnieżdżona klasa

  • Nie można uzyskać dostępu do metod lub pól instancji klasy zewnętrznej

  • Nie jest powiązany z żadnym wystąpieniem obejmującym klasę. Aby go utworzyć:

    OuterClass.StaticNestedClass nestedObject = new OuterClass.StaticNestedClass();

Podobieństwa

  • Obie klasy wewnętrzne mogą uzyskać dostęp nawet prywatnych pól i metod z klasy zewnętrznej
  • Również klasa zewnętrzna mają dostęp do prywatnych pól i metod z klas wewnętrznych
  • Obie klasy mogą mieć prywatny, chroniony lub publiczny modyfikator dostępu

Dlaczego warto korzystać z klas zagnieżdżonych?

Według dokumentacji Oracle istnieje kilka powodów ( pełna dokumentacja ):

  • Jest to sposób logicznego grupowania klas, które są używane tylko w jednym miejscu: jeśli klasa jest użyteczna tylko dla jednej innej klasy, logiczne jest osadzenie jej w tej klasie i utrzymanie dwóch razem. Zagnieżdżanie takich „klas pomocniczych” upraszcza ich pakiet.

  • Zwiększa enkapsulację: Rozważ dwie klasy najwyższego poziomu, A i B, w których B potrzebuje dostępu do członków A, które w innym przypadku zostałyby uznane za prywatne. Ukrywając klasę B w klasie A, członkowie A mogą zostać uznani za prywatnych, a B może uzyskać do nich dostęp. Ponadto sam B można ukryć przed światem zewnętrznym.

  • Może to prowadzić do bardziej czytelnego i łatwego do utrzymania kodu: zagnieżdżanie małych klas w klasach najwyższego poziomu przybliża kod do miejsca, w którym jest używany.

Behzad Bahmanyar
źródło
26

Myślę, że konwencja, która jest ogólnie przestrzegana, jest następująca:

  • klasa statyczna w klasie najwyższego poziomu jest klasą zagnieżdżoną
  • klasa niestatyczna w klasie najwyższego poziomu jest klasą wewnętrzną , która ponadto ma jeszcze dwie postaci:
    • klasa lokalna - nazwane klasy zadeklarowane wewnątrz bloku, takie jak metoda lub treść konstruktora
    • klasa anonimowa - klasy bez nazwy, których instancje są tworzone w wyrażeniach i instrukcjach

Jednak kilka innych punktów do zapamiętania to:

  • Klasy najwyższego poziomu i statyczna klasa zagnieżdżona są semantycznie takie same, z tym wyjątkiem, że w przypadku statycznej klasy zagnieżdżonej może ona odwoływać się statycznie do prywatnych pól statycznych / metod swojej zewnętrznej klasy [macierzystej] i odwrotnie.

  • Klasy wewnętrzne mają dostęp do zmiennych instancji obejmującej instancję klasy zewnętrznej [nadrzędnej]. Jednak nie wszystkie klasy wewnętrzne mają instancje zamykające, na przykład klasy wewnętrzne w kontekstach statycznych, takie jak klasa anonimowa używana w statycznym bloku inicjującym, nie mają takiej możliwości.

  • Klasa anonimowa domyślnie rozszerza klasę nadrzędną lub implementuje interfejs nadrzędny i nie ma dalszej klauzuli, aby rozszerzyć inną klasę lub zaimplementować więcej interfejsów. Więc,

    • new YourClass(){}; znaczy class [Anonymous] extends YourClass {}
    • new YourInterface(){}; znaczy class [Anonymous] implements YourInterface {}

Czuję, że tym większym pytaniem pozostaje otwarte, które z nich użyć i kiedy? Cóż, to głównie zależy od tego, z jakim scenariuszem masz do czynienia, ale przeczytanie odpowiedzi udzielonej przez @jrudolph może pomóc ci podjąć decyzję.

sactiw
źródło
15

Klasa zagnieżdżona: klasa wewnątrz klasy

Rodzaje:

  1. Statycznie zagnieżdżona klasa
  2. Niestatyczna klasa zagnieżdżona [klasa wewnętrzna]

Różnica:

Niestatyczna klasa zagnieżdżona [klasa wewnętrzna]

W niestatycznej klasie zagnieżdżonej obiekt klasy wewnętrznej istnieje w obiekcie klasy zewnętrznej. Tak więc element danych klasy zewnętrznej jest dostępny dla klasy wewnętrznej. Aby więc stworzyć obiekt klasy wewnętrznej, musimy najpierw stworzyć obiekt klasy zewnętrznej.

outerclass outerobject=new outerobject();
outerclass.innerclass innerobjcet=outerobject.new innerclass(); 

Statycznie zagnieżdżona klasa

W statycznej klasie zagnieżdżonej obiekt klasy wewnętrznej nie potrzebuje obiektu klasy zewnętrznej, ponieważ słowo „statyczny” oznacza brak potrzeby tworzenia obiektu.

class outerclass A {
    static class nestedclass B {
        static int x = 10;
    }
}

Jeśli chcesz uzyskać dostęp do x, napisz następującą metodę wewnętrzną

  outerclass.nestedclass.x;  i.e. System.out.prinltn( outerclass.nestedclass.x);
tejas
źródło
13

Instancja klasy wewnętrznej jest tworzona, gdy tworzona jest instancja klasy zewnętrznej. Dlatego członkowie i metody klasy wewnętrznej mają dostęp do elementów i metod instancji (obiektu) klasy zewnętrznej. Kiedy instancja klasy zewnętrznej wykracza poza zakres, również instancje klasy wewnętrznej przestają istnieć.

Statyczna klasa zagnieżdżona nie ma konkretnej instancji. Jest po prostu ładowany, gdy jest używany po raz pierwszy (podobnie jak metody statyczne). Jest to całkowicie niezależna jednostka, której metody i zmienne nie mają żadnego dostępu do instancji klasy zewnętrznej.

Statyczne zagnieżdżone klasy nie są sprzężone z obiektem zewnętrznym, są szybsze i nie zajmują pamięci sterty / stosu, ponieważ nie jest konieczne tworzenie instancji takiej klasy. Dlatego podstawową zasadą jest próba zdefiniowania statycznej zagnieżdżonej klasy o możliwie ograniczonym zakresie (prywatny> = klasa> = chroniony> = publiczny), a następnie konwersja do klasy wewnętrznej (poprzez usunięcie „statycznego” identyfikatora) i poluzowanie zakres, jeśli jest to naprawdę konieczne.

rmaruszewski
źródło
2
Pierwsze zdanie jest niepoprawne. Nie ma czegoś takiego jak „ na przykład wewnętrznej klasy”, a przypadki to mogą być tworzone w dowolnym momencie po zewnętrznej klasa została instancję. Drugie zdanie nie wynika z pierwszego zdania.
user207421
11

Istnieje subtelność dotycząca użycia zagnieżdżonych klas statycznych, które mogą być przydatne w niektórych sytuacjach.

Podczas gdy atrybuty statyczne są tworzone, zanim klasa zostanie utworzona za pomocą swojego konstruktora, atrybuty statyczne w zagnieżdżonych klasach statycznych nie wydają się być tworzone, dopóki nie zostanie wywołany konstruktor klasy, a przynajmniej nie po pierwszym odwołaniu do atrybutów, nawet jeśli są oznaczone jako „ostateczne”.

Rozważ ten przykład:

public class C0 {

    static C0 instance = null;

    // Uncomment the following line and a null pointer exception will be
    // generated before anything gets printed.
    //public static final String outerItem = instance.makeString(98.6);

    public C0() {
        instance = this;
    }

    public String makeString(int i) {
        return ((new Integer(i)).toString());
    }

    public String makeString(double d) {
        return ((new Double(d)).toString());
    }

    public static final class nested {
        public static final String innerItem = instance.makeString(42);
    }

    static public void main(String[] argv) {
        System.out.println("start");
        // Comment out this line and a null pointer exception will be
        // generated after "start" prints and before the following
        // try/catch block even gets entered.
        new C0();
        try {
            System.out.println("retrieve item: " + nested.innerItem);
        }
        catch (Exception e) {
            System.out.println("failed to retrieve item: " + e.toString());
        }
        System.out.println("finish");
    }
}

Mimo że zarówno „zagnieżdżone”, jak i „wewnętrznaItem” są zadeklarowane jako „statyczne końcowe”. ustawienie nested.innerItem ma miejsce dopiero po utworzeniu instancji klasy (a przynajmniej dopiero po pierwszym odwołaniu do zagnieżdżonego elementu statycznego), jak można to zobaczyć, komentując i usuwając komentarz z wierszy, do których się odwołuję, powyżej. To samo nie dotyczy prawdy „outerItem”.

Przynajmniej to widzę w Javie 6.0.

HippoMan
źródło
10

Terminy są używane zamiennie. Jeśli chcesz być naprawdę pedantyczny o nim, to mógłby zdefiniować „zagnieżdżone klasy” odnosi się do statycznego klasy wewnętrznej, która nie ma jednej instancji otaczającą. W kodzie możesz mieć coś takiego:

public class Outer {
    public class Inner {}

    public static class Nested {}
}

To nie jest tak naprawdę powszechnie przyjęta definicja.

Daniel Spiewak
źródło
2
„static static” jest wewnętrznie sprzecznością.
user207421,
5
Nie konwencja definiuje klasę wewnętrzną jako niestatyczną klasę zagnieżdżoną, ale JLS. docs.oracle.com/javase/specs/jls/se8/html/jls-8.html#jls-8.1.3
Lew Bloch
1
Terminy te nie są „używane zamiennie”.
user207421,
dlaczego statyczny w powyższym przykładzie podaje błąd w ide
DeV
10

W przypadku tworzenia instancji instancja niestatycznej klasy wewnętrznej jest tworzona za pomocą odwołania do obiektu klasy zewnętrznej, w którym jest zdefiniowana. Oznacza to, że zawiera instancję. Ale instancja statycznej klasy wewnętrznej jest tworzona z referencją klasy zewnętrznej, a nie z referencją obiektu klasy zewnętrznej. Oznacza to, że nie zawiera on instancji.

Na przykład:

class A
{
  class B
  {
    // static int x; not allowed here…..    
  }
  static class C
  {
    static int x; // allowed here
  }
}

class Test
{
  public static void main(String str)
  {
    A o=new A();
    A.B obj1 =o.new B();//need of inclosing instance

    A.C obj2 =new A.C();

    // not need of reference of object of outer class….
  }
}
Ankit Jain
źródło
1
„static static” jest wewnętrznie sprzecznością. Zagnieżdżona klasa jest statyczna lub wewnętrzna.
user207421
9

Nie sądzę, aby można było tu wiele dodać, większość odpowiedzi doskonale wyjaśnia różnice między statyczną klasą zagnieżdżoną a klasami wewnętrznymi. Należy jednak wziąć pod uwagę następujący problem podczas korzystania z klas zagnieżdżonych a klas wewnętrznych. Jak wspomina w kilku odpowiedziach Klasy wewnętrzne nie może być instancja bez i wystąpienie ich załączając klasy co oznacza, że HOLD jest wskaźnik do instancji swojej klasie otaczającą, która może prowadzić do przepełnienia pamięci lub wyjątek przepełnienie stosu ze względu na fakt, GC nie będzie w stanie wyrzucić śmieci do otaczających klas, nawet jeśli nie będą już używane. Aby to wyjaśnić, sprawdź następujący kod:

public class Outer {


    public  class Inner {

    }


    public Inner inner(){
        return new Inner();
    }

    @Override
    protected void finalize() throws Throwable {
    // as you know finalize is called by the garbage collector due to destroying an object instance
        System.out.println("I am destroyed !");
    }
}


public static void main(String arg[]) {

    Outer outer = new Outer();
    Outer.Inner inner = outer.new Inner();

    // out instance is no more used and should be garbage collected !!!
    // However this will not happen as inner instance is still alive i.e used, not null !
    // and outer will be kept in memory until inner is destroyed
    outer = null;

    //
    // inner = null;

    //kick out garbage collector
    System.gc();

}

Jeśli usuniesz komentarz na temat // inner = null;: Program wyda komunikat „ Jestem zniszczony! ”, Ale zachowanie tego komentarza nie spowoduje.
Powodem jest to, że biała wewnętrzna instancja jest nadal wywoływana, GC nie może jej zebrać, a ponieważ odwołuje się (ma wskaźnik) do zewnętrznej instancji, nie jest również gromadzona. Mając wystarczającą liczbę tych obiektów w projekcie i może zabraknąć pamięci.
W porównaniu ze statycznymi klasami wewnętrznymi, które nie utrzymują punktu do instancji klasy wewnętrznej, ponieważ nie jest ona związana z instancją, ale jest związana z klasą. Powyższy program może wypisać komunikat „ Jestem zniszczony! ”, Jeśli uczynisz klasę wewnętrzną statyczną i utworzoną przy pomocy instancjiOuter.Inner i = new Outer.Inner();

Adelina
źródło
8

Ummm ... klasa wewnętrzna JEST klasą zagnieżdżoną ... masz na myśli klasę anonimową i klasę wewnętrzną?

Edycja: Jeśli faktycznie miałeś na myśli wewnętrzną vs anonimową ... klasa wewnętrzna to po prostu klasa zdefiniowana w klasie, takiej jak:

public class A {
    public class B {
    }
}

Podczas gdy klasa anonimowa jest rozszerzeniem klasy zdefiniowanej anonimowo, więc nie zdefiniowano żadnej rzeczywistej klasy, jak w:

public class A {
}

A anon = new A() { /* you could change behavior of A here */ };

Dalsza edycja:

Wikipedia twierdzi, że jest różnica w Javie, ale pracuję z Javą od 8 lat i po raz pierwszy usłyszałem takie rozróżnienie ... nie wspominając o tym, że nie ma tam żadnych referencji na poparcie roszczenia ... na dole linia, klasa wewnętrzna to klasa zdefiniowana w klasie (statyczna lub nie), a zagnieżdżona jest tylko innym terminem oznaczającym to samo.

Istnieje subtelna różnica między statyczną i niestatyczną klasą zagnieżdżoną ... w zasadzie nie-statyczne klasy wewnętrzne mają niejawny dostęp do pól instancji i metod klasy otaczającej (dlatego nie można ich budować w kontekście statycznym, będzie to kompilator błąd). Z drugiej strony statyczne klasy zagnieżdżone nie mają niejawnego dostępu do pól i metod instancji i mogą być konstruowane w kontekście statycznym.

Mike Stone
źródło
3
Zgodnie z dokumentacją Java istnieje różnica między klasą wewnętrzną a statyczną klasą zagnieżdżoną - statyczne klasy zagnieżdżone nie mają odniesień do swojej klasy zamykającej i są używane głównie do celów organizacyjnych. Powinieneś zobaczyć odpowiedź Jegschemescha, aby uzyskać bardziej szczegółowy opis.
mipadi
1
Myślę, że różnica semantyczna jest głównie historyczna. Kiedy napisałem kompilator C # -> Java 1.1, odniesienie do języka Java było bardzo wyraźne: klasa zagnieżdżona jest statyczna, klasa wewnętrzna nie (i dlatego ma 0 $). W każdym razie jest to mylące i cieszę się, że to już nie problem.
Tomer Gabel
2
JLS definiuje „klasę wewnętrzną” w docs.oracle.com/javase/specs/jls/se8/html/jls-8.html#jls-8.1.3 i dlatego niemożliwe jest posiadanie niestatycznej „wewnętrznej” klasa ”w Javie. „Zagnieżdżony” NIE jest „tylko innym terminem oznaczającym to samo” i NIE PRAWDA, że „klasa wewnętrzna jest klasą zdefiniowaną w klasie (statycznej lub nie)”. To NIEPRAWIDŁOWA informacja.
Lew Bloch,
6

Kierowanie na ucznia, który jest nowicjuszem w Javie i / lub zagnieżdżonych klasach

Klasy zagnieżdżone mogą być:
1. Statyczne klasy zagnieżdżone.
2. Niestatyczne klasy zagnieżdżone. (znany również jako klasy wewnętrzne ) => Pamiętaj o tym


1. Klasy wewnętrzne
Przykład:

class OuterClass  {
/*  some code here...*/
     class InnerClass  {  }
/*  some code here...*/
}


Klasy wewnętrzne to podzbiory klas zagnieżdżonych:

  • klasa wewnętrzna to specyficzny typ klasy zagnieżdżonej
  • klasy wewnętrzne to podzbiory klas zagnieżdżonych
  • Możesz powiedzieć, że klasa wewnętrzna jest również klasą zagnieżdżoną, ale NIE możesz powiedzieć, że klasa zagnieżdżona jest również klasą wewnętrzną .

Specjalność klasy wewnętrznej:

  • instancja klasy wewnętrznej ma dostęp do wszystkich członków klasy zewnętrznej, nawet tych oznaczonych jako „prywatne”


2.Statyczne zagnieżdżone klasy:
przykład:

class EnclosingClass {
  static class Nested {
    void someMethod() { System.out.println("hello SO"); }
  }
}

Przypadek 1: Tworzenie instancji statycznej klasy zagnieżdżonej z klasy nieobjętej klauzulą

class NonEnclosingClass {

  public static void main(String[] args) {
    /*instantiate the Nested class that is a static
      member of the EnclosingClass class:
    */

    EnclosingClass.Nested n = new EnclosingClass.Nested(); 
    n.someMethod();  //prints out "hello"
  }
}

Przypadek 2: Tworzenie instancji statycznej klasy zagnieżdżonej z klasy zamykającej

class EnclosingClass {

  static class Nested {
    void anotherMethod() { System.out.println("hi again"); } 
  }

  public static void main(String[] args) {
    //access enclosed class:

    Nested n = new Nested(); 
    n.anotherMethod();  //prints out "hi again"
  }

}

Specjalność klas statycznych:

  • Statyczna klasa wewnętrzna miałaby dostęp tylko do statycznych elementów klasy zewnętrznej i nie miałaby dostępu do elementów niestatycznych.

Wniosek:
Pytanie: Jaka jest główna różnica między klasą wewnętrzną a statyczną klasą zagnieżdżoną w Javie?
Odpowiedź: wystarczy przejrzeć specyfikę każdej klasy wspomnianej powyżej.

VdeX
źródło
6

Zarówno klasa wewnętrzna, jak i zagnieżdżona klasa statyczna w Javie są klasami zadeklarowanymi w innej klasie, znanej jako klasa najwyższego poziomu w Javie. W terminologii Java, jeśli zadeklarujesz klasę zagnieżdżoną jako statyczną, będzie ona nazywana klasą zagnieżdżoną w Javie, podczas gdy niestatyczna klasa zagnieżdżona będzie po prostu nazywana klasą wewnętrzną.

Co to jest klasa wewnętrzna w Javie?

Każda klasa, która nie jest najwyższego poziomu lub nie została zadeklarowana w innej klasie, jest znana jako klasa zagnieżdżona, a spośród tych klas zagnieżdżonych, które są zadeklarowane jako niestatyczne, są znane jako klasa wewnętrzna w Javie. istnieją trzy rodzaje klasy wewnętrznej w Javie:

1) Lokalna klasa wewnętrzna - deklarowana w bloku kodu lub metodzie.
2) Anonimowa klasa wewnętrzna - to klasa, która nie ma nazwy, do której można się odwoływać i jest inicjowana w tym samym miejscu, w którym została utworzona.
3) Członek klasy wewnętrznej - deklarowany jako niestatyczny element klasy zewnętrznej.

public class InnerClassTest {
    public static void main(String args[]) {      
        //creating local inner class inside method i.e. main() 
        class Local {
            public void name() {
                System.out.println("Example of Local class in Java");

            }
        }      
        //creating instance of local inner class
        Local local = new Local();
        local.name(); //calling method from local inner class

        //Creating anonymous inner class in Java for implementing thread
        Thread anonymous = new Thread(){
            @Override
            public void run(){
                System.out.println("Anonymous class example in java");
            }
        };
        anonymous.start();

        //example of creating instance of inner class
        InnerClassTest test = new InnerClassTest();
        InnerClassTest.Inner inner = test.new Inner();
        inner.name(); //calling method of inner class
    }

     //Creating Inner class in Java
    private class Inner{
        public void name(){
            System.out.println("Inner class example in java");
        }
    }
}

Co to jest zagnieżdżona klasa statyczna w Javie?

Zagnieżdżona klasa statyczna to kolejna klasa zadeklarowana w klasie jako element członkowski i uczyniona statyczną. Zagnieżdżona klasa statyczna jest również zadeklarowana jako członek klasy zewnętrznej i może być prywatna, publiczna lub chroniona jak każdy inny element. Jedną z głównych zalet zagnieżdżonej klasy statycznej w porównaniu z klasą wewnętrzną jest to, że instancja zagnieżdżonej klasy statycznej nie jest dołączona do żadnej otaczającej instancji klasy zewnętrznej. Nie potrzebujesz również żadnego wystąpienia klasy zewnętrznej, aby utworzyć wystąpienie zagnieżdżonej klasy statycznej w Javie .

1) Może uzyskać dostęp do danych statycznych należących do klasy zewnętrznej, w tym prywatnych.
2) Statycznie zagnieżdżona klasa nie może uzyskać dostępu do elementu lub metody niestatycznej (instancji) .

public class NestedStaticExample {
    public static void main(String args[]){  
        StaticNested nested = new StaticNested();
        nested.name();
    }  
    //static nested class in java
    private static class StaticNested{
        public void name(){
            System.out.println("static nested class example in java");
        }
    }
}

Ref: Klasa wewnętrzna i zagnieżdżona klasa statyczna w Javie z przykładem

roottraveller
źródło
2
„Statycznie zagnieżdżona klasa nie może uzyskać dostępu do elementu lub metody danych statycznych (instancja)”. jest niepoprawny i powoduje zamieszanie . Absolutnie mają dostęp do prywatnych informacji o instancji - pod warunkiem, że utworzą instancję, aby uzyskać dostęp do informacji o tej instancji. Nie mają zamkniętej instancji, podobnie jak klasy wewnętrzne, ale mają dostęp do prywatnych członków instancji klasy zamykającej.
TJ Crowder
5

Myślę, że ludzie tutaj powinni zauważyć, że: Statyczna klasa gniazd to tylko pierwsza klasa wewnętrzna. Na przykład:

 public static class A {} //ERROR

 public class A {
     public class B {
         public static class C {} //ERROR
     }
 }

 public class A {
     public static class B {} //COMPILE !!!

 }

Podsumowując, klasa statyczna nie zależy od tego, która klasa zawiera. Nie mogą więc w normalnej klasie. (ponieważ normalna klasa potrzebuje instancji).

hqt
źródło
2
To wszystko jest nonsensem. Wszystko to pokazuje, że klasa wewnętrzna nie może zawierać klasy statycznej. Część o „nie zależy od tego, która klasa zawiera” jest bez znaczenia, podobnie jak poniższe zdanie.
user207421,
5

Kiedy deklarujemy statyczną klasę członka w klasie, jest ona znana jako klasa zagnieżdżona najwyższego poziomu lub statyczna klasa zagnieżdżona. Można to wykazać jak poniżej:

class Test{
    private static int x = 1;
        static class A{
        private static int y = 2;
        public static int getZ(){
            return B.z+x;
        }
    }
    static class B{
        private static int z = 3;
        public static int getY(){
            return A.y;
        }
    }
}

class TestDemo{
     public static void main(String[] args){
        Test t = new Test();
        System.out.println(Test.A.getZ());
        System.out.println(Test.B.getY());
    }
}

Kiedy deklarujemy niestatyczną klasę członka w klasie, jest to znane jako klasa wewnętrzna. Klasa wewnętrzna może być pokazana jak poniżej:

    class Test{
        private int i = 10;
        class A{
            private int i =20;
            void display(){
            int i = 30;
            System.out.println(i);
            System.out.println(this.i);
            System.out.println(Test.this.i);
        }
    }
}
Pankti
źródło
„Kiedy deklarujemy statyczną klasę członka w klasie, jest to znane jako zagnieżdżona klasa najwyższego poziomu”. To nie ma sensu. Klasa najwyższego poziomu to klasa, która nie jest klasą zagnieżdżoną”. Nie ma czegoś takiego jak „klasa zagnieżdżona najwyższego poziomu”.
Radiodef,
3

Oto przykład static nested classi inner class:

OuterClass.java

public class OuterClass {
     private String someVariable = "Non Static";

     private static String anotherStaticVariable = "Static";  

     OuterClass(){

     }

     //Nested classes are static
     static class StaticNestedClass{
        private static String privateStaticNestedClassVariable = "Private Static Nested Class Variable"; 

        //can access private variables declared in the outer class
        public static void getPrivateVariableofOuterClass(){
            System.out.println(anotherStaticVariable);
        }
     }

     //non static
     class InnerClass{

         //can access private variables of outer class
         public String getPrivateNonStaticVariableOfOuterClass(){
             return someVariable;
         }
     }

     public static void accessStaticClass(){
         //can access any variable declared inside the Static Nested Class 
         //even if it private
         String var = OuterClass.StaticNestedClass.privateStaticNestedClassVariable; 
         System.out.println(var);
     }

}

OuterClassTest:

public class OuterClassTest {
    public static void main(String[] args) {

        //access the Static Nested Class
        OuterClass.StaticNestedClass.getPrivateVariableofOuterClass();

        //test the private variable declared inside the static nested class
        OuterClass.accessStaticClass();
        /*
         * Inner Class Test
         * */

        //Declaration

        //first instantiate the outer class
        OuterClass outerClass = new OuterClass();

        //then instantiate the inner class
        OuterClass.InnerClass innerClassExample =  outerClass. new InnerClass();

        //test the non static private variable
        System.out.println(innerClassExample.getPrivateNonStaticVariableOfOuterClass()); 

    }

}
Pritam Banerjee
źródło
3

Myślę, że żadna z powyższych odpowiedzi nie daje prawdziwego przykładu różnicy między klasą zagnieżdżoną a statyczną klasą zagnieżdżoną pod względem projektowania aplikacji. Główną różnicą między statyczną klasą zagnieżdżoną a klasą wewnętrzną jest możliwość dostępu do zewnętrznego pola instancji klasy.

Rzućmy okiem na dwa następujące przykłady.

Statyczna klasa zagnieżdżenia: Dobrym przykładem użycia statycznych zagnieżdżonych klas jest wzorzec konstruktora ( https://dzone.com/articles/design-patterns-the-builder-pattern ).

W przypadku BankAccount używamy statycznej zagnieżdżonej klasy, głównie dlatego, że

  1. Przed klasą zewnętrzną można utworzyć statyczną instancję klasy gniazda.

  2. We wzorcu konstruktora konstruktor jest klasą pomocniczą, która służy do tworzenia konta bankowego.

  3. BankAccount.Builder jest powiązany tylko z BankAccount. Żadne inne klasy nie są powiązane z BankAccount.Builder. więc lepiej je uporządkować bez użycia konwencji nazw.
public class BankAccount {

    private long accountNumber;
    private String owner;
    ...

    public static class Builder {

    private long accountNumber;
    private String owner;
    ...

    static public Builder(long accountNumber) {
        this.accountNumber = accountNumber;
    }

    public Builder withOwner(String owner){
        this.owner = owner;
        return this; 
    }

    ...
    public BankAccount build(){
            BankAccount account = new BankAccount(); 
            account.accountNumber = this.accountNumber;
            account.owner = this.owner;
            ...
            return account;
        }
    }
}

Klasa wewnętrzna: powszechnym zastosowaniem klas wewnętrznych jest definiowanie modułu obsługi zdarzeń. https://docs.oracle.com/javase/tutorial/uiswing/events/generalrules.html

W przypadku MyClass używamy klasy wewnętrznej, głównie dlatego, że:

  1. Klasa wewnętrzna MyAdapter musi uzyskać dostęp do elementu klasy zewnętrznej.

  2. W tym przykładzie MyAdapter jest powiązany tylko z MyClass. Żadne inne klasy nie są powiązane z MyAdapter. więc lepiej zorganizować je razem bez użycia konwencji nazw

public class MyClass extends Applet {
    ...
        someObject.addMouseListener(new MyAdapter());
    ...
    class MyAdapter extends MouseAdapter {
        public void mouseClicked(MouseEvent e) {
            ...// Event listener implementation goes here...
            ...// change some outer class instance property depend on the event
        }
    }
}
Leogao
źródło
2

Schemat

wprowadź opis zdjęcia tutaj

Główną różnicą pomiędzy static nestedi non-static nestedklas jest to, że static nested nie ma dostępu do non-statycznych członków klasy zewnętrzny

yoAlex5
źródło
0

Przede wszystkim nie ma takiej klasy zwanej klasą statyczną. Używanie modyfikatora statycznego z klasą wewnętrzną (zwaną klasą zagnieżdżoną) mówi, że jest to element statyczny klasy zewnętrznej, co oznacza, że ​​możemy uzyskać do niej dostęp tak jak w przypadku innych elementów statycznych i nie posiadając żadnych wystąpienie klasy zewnętrznej. (Co jest początkowo zaletą statyczną.)

Różnica między używaniem klasy zagnieżdżonej a zwykłą klasą wewnętrzną jest następująca:

OuterClass.InnerClass inner = new OuterClass().new InnerClass();

Najpierw możemy utworzyć instancję klasy zewnętrznej, a następnie możemy uzyskać dostęp do wewnętrznej.

Ale jeśli zagnieżdżona jest klasa, wówczas składnia jest następująca:

OuterClass.InnerClass inner = new OuterClass.InnerClass();

Który używa składni statycznej jako normalnej implementacji słowa kluczowego static.

Sohi
źródło
1
„... mówi, że jest to statyczny element klasy zewnętrznej, co oznacza ...”: Nie jest błędem myśleć o statycznej klasie zagnieżdżonej jako „klasie elementu klasy zewnętrznej”, ale podobieństwa z polami statycznymi i metody kończą się na tym. Statycznie zagnieżdżona klasa nie „należy” do klasy zewnętrznej. Niemal pod każdym względem, który ma znaczenie, statyczna klasa zagnieżdżona to wolnostojąca klasa najwyższego poziomu, której definicja klasy została zagnieżdżona w definicji klasy zewnętrznej dla wygody pakowania (i, miejmy nadzieję, ponieważ istnieje logiczne powiązanie między klasą zagnieżdżoną a klasą zewnętrzną ... chociaż nie musi być).
scottb
1
„static static” jest wewnętrznie sprzecznością. Klasy statyczne istnieją na pierwszym poziomie zagnieżdżenia i z definicji nie są klasami wewnętrznymi. Bardzo zdezorientowany.
user207421,
0

Język programowania Java pozwala zdefiniować klasę w innej klasie. Taka klasa nazywa się klasą zagnieżdżoną i jest zilustrowana tutaj:

class OuterClass {
...
class NestedClass {
    ...
    }
}

Klasy zagnieżdżone są podzielone na dwie kategorie: statyczne i niestatyczne. Klasy zagnieżdżone, które są zadeklarowane jako statyczne, nazywane są statycznymi klasami zagnieżdżonymi. Niestatyczne klasy zagnieżdżone nazywane są klasami wewnętrznymi. Jedną z rzeczy, o których powinniśmy pamiętać, jest to, że statyczne klasy zagnieżdżone (klasy wewnętrzne) mają dostęp do innych członków klasy zamykającej, nawet jeśli są one uznane za prywatne. Statycznie zagnieżdżone klasy mają dostęp do innych członków klasy zamykającej tylko wtedy, gdy są statyczne. Nie ma dostępu do niestatycznych członków klasy zewnętrznej. Podobnie jak w przypadku metod i zmiennych klas, statycznie zagnieżdżona klasa jest powiązana z jej klasą zewnętrzną. Na przykład, aby utworzyć obiekt dla statycznej klasy zagnieżdżonej, użyj następującej składni:

OuterClass.StaticNestedClass nestedObject =
 new OuterClass.StaticNestedClass(); 

Aby utworzyć instancję klasy wewnętrznej, musisz najpierw utworzyć instancję klasy zewnętrznej. Następnie utwórz wewnętrzny obiekt w obrębie zewnętrznego obiektu za pomocą następującej składni:

OuterClass.InnerClass innerObject = new OuterClass().new InnerClass();

Dlaczego używamy zagnieżdżonych klas

  1. Jest to sposób logicznego grupowania klas używanych tylko w jednym miejscu.
  2. Zwiększa kapsułkowanie.
  3. Może to prowadzić do bardziej czytelnego i łatwego do utrzymania kodu.

Źródło: The Java ™ Tutorials - Nested Classes

Mithun Debnath
źródło
-1

Różnica polega na tym, że deklaracja klasy zagnieżdżonej, która jest również statyczna, może być utworzona instancji poza klasą otaczającą.

Jeśli masz zagnieżdżoną deklarację klasy, która nie jest statyczna, zwana także klasą wewnętrzną , Java nie pozwoli na utworzenie jej, chyba że za pośrednictwem klasy otaczającej. Obiekt utworzony z klasy wewnętrznej jest powiązany z obiektem utworzonym z klasy zewnętrznej, więc klasa wewnętrzna może odwoływać się do pól zewnętrznej.

Ale jeśli jest statyczny, to łącze nie istnieje, nie można uzyskać dostępu do zewnętrznych pól (z wyjątkiem zwykłego odwołania, jak każdy inny obiekt), a zatem można utworzyć instancję samej klasy zagnieżdżonej.

DigitalRoss
źródło
1
To nieprawda. Istnieje specjalna składnia do tworzenia klasy wewnętrznej poza zakresem klasy zamykającej.
user207421,
-1

Jest dość prosty, porównując statyczne klasy lokalne i niestatyczne klasy wewnętrzne
Różnice:
Statyczna klasa lokalna:
Może uzyskać dostęp tylko do statycznych członków klasy zewnętrznej.
Nie można mieć statycznych inicjatorów
Nie można uzyskać dostępu bezpośrednio spoza funkcji, w której jest zadeklarowana

Lau C
źródło
-2

Zilustrowałem różne możliwe scenariusze poprawek i błędów, które mogą wystąpić w kodzie Java.

    class Outter1 {

        String OutStr;

        Outter1(String str) {
            OutStr = str;
        }

        public void NonStaticMethod(String st)  {

            String temp1 = "ashish";
            final String  tempFinal1 = "ashish"; 

            //  below static attribute not permitted
            // static String tempStatic1 = "static";    

            //  below static with final attribute not permitted         
            // static final String  tempStatic1 = "ashish";  

            // synchronized keyword is not permitted below          
            class localInnerNonStatic1 {            

                synchronized    public void innerMethod(String str11) {
                    str11 = temp1 +" sharma";
                    System.out.println("innerMethod ===> "+str11);
                }

                /* 
        //  static method with final not permitted
          public static void innerStaticMethod(String str11) { 

                    str11 = temp1 +" india";
                    System.out.println("innerMethod ===> "+str11);
                }*/
            }

            // static class not permitted below
            //  static class localInnerStatic1 {   }                            

        }

        public static  void StaticMethod(String st)     {

            String temp1 = "ashish";
            final String  tempFinal1 = "ashish"; 

            // static attribute not permitted below
            //static String tempStatic1 = "static";     

            //  static with final attribute not permitted below
            // static final String  tempStatic1 = "ashish";                         

            class localInnerNonStatic1 {
                public void innerMethod(String str11) {
                    str11 = temp1 +" sharma";
                    System.out.println("innerMethod ===> "+str11);
                }

                /*
    // static method with final not permitted
    public static void innerStaticMethod(String str11) {  
                    str11 = temp1 +" india";
                    System.out.println("innerMethod ===> "+str11);
                }*/
            }

            // static class not permitted below
            //  static class localInnerStatic1 {   }    

        }

        // synchronized keyword is not permitted
        static  class inner1 {          

            static String  temp1 = "ashish";
            String  tempNonStatic = "ashish";
            // class localInner1 {

            public void innerMethod(String str11) {
                str11 = temp1 +" sharma";
                str11 = str11+ tempNonStatic +" sharma";
                System.out.println("innerMethod ===> "+str11);
            }

            public static void innerStaticMethod(String str11) {
                //  error in below step
                str11 = temp1 +" india";    
                //str11 = str11+ tempNonStatic +" sharma";
                System.out.println("innerMethod ===> "+str11);
            }
            //}
        }

        //synchronized keyword is not permitted below
        class innerNonStatic1 {             

//This is important we have to keep final with static modifier in non
// static innerclass below
            static final String  temp1 = "ashish";  
            String  tempNonStatic = "ashish";
            // class localInner1 {

            synchronized    public void innerMethod(String str11) {
                tempNonStatic = tempNonStatic +" ...";
                str11 = temp1 +" sharma";
                str11 = str11+ tempNonStatic +" sharma";
                System.out.println("innerMethod ===> "+str11);
            }

            /*
            //  error in below step
            public static void innerStaticMethod(String str11) {   
                            //  error in below step
                            // str11 = tempNonStatic +" india";                     
                            str11 = temp1 +" india";
                            System.out.println("innerMethod ===> "+str11);
                        }*/
                    //}
                }
    }
Ashish Sharma
źródło
1
Oczywiście część kodu. I na wypadek, gdybyś nie zauważył: twój przykład kodu jest bardzo trudny do odczytania. Nawet na moim ogromnym monitorze stacjonarnym mam poziomy pasek przewijania. Zastanów się nad umieszczeniem swoich komentarzy powyżej lub poniżej tego, co komentują - zamiast z tyłu .
GhostCat,