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?
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?
Odpowiedzi:
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.
import OuterClass.StaticNestedClass;
następnie odwołaj się do klasy tak jak OuterClass.
OuterClass.InnerClass innerObject = outerObject.new InnerClass();
?
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ę:
Istnieją cztery rodzaje zagnieżdżonych klas w Javie . W skrócie są to:
Pozwól mi rozwinąć bardziej szczegółowo.
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.
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 .
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ć.
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ą.
Nie sądzę, aby prawdziwa różnica stała się jasna w powyższych odpowiedziach.
Najpierw popraw warunki:
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.
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:
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.
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.
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 .
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 public
lub 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 {
}
}
Inner1
jest naszą statyczną klasą wewnętrzną i Inner2
jest naszą klasą wewnętrzną, która nie jest statyczna. Kluczową różnicą między nimi jest to, że nie można utworzyć Inner2
instancji bez Outera, ponieważ można utworzyć Inner1
obiekt niezależnie.
Kiedy używałbyś klasy wewnętrznej?
Pomyśl o sytuacji, w której Class A
i Class B
są powiązane, Class B
muszą uzyskać dostęp do Class A
członków i Class B
są 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.
OuterClass.Inner2 inner = outer.new Inner2();
?
static inner
jest sprzecznością pod względem.
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!
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ż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();
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.
Myślę, że konwencja, która jest ogólnie przestrzegana, jest następująca:
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ę.
Klasa zagnieżdżona: klasa wewnątrz klasy
Rodzaje:
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);
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.
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.
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.
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….
}
}
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();
Klasa zagnieżdżona jest bardzo ogólnym terminem: każda klasa, która nie jest najwyższym poziomem, jest klasą zagnieżdżoną. Klasa wewnętrzna to niestatyczna klasa zagnieżdżona. Joseph Darcy napisał bardzo ładne wyjaśnienie na temat klas zagnieżdżonych, wewnętrznych, członkowskich i klas najwyższego poziomu .
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.
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:
Specjalność klasy wewnętrznej:
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:
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.
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
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).
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);
}
}
}
Oto przykład static nested class
i 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());
}
}
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
Przed klasą zewnętrzną można utworzyć statyczną instancję klasy gniazda.
We wzorcu konstruktora konstruktor jest klasą pomocniczą, która służy do tworzenia konta bankowego.
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:
Klasa wewnętrzna MyAdapter musi uzyskać dostęp do elementu klasy zewnętrznej.
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
}
}
}
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.
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
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.
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
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);
}*/
//}
}
}
item 22 : Favor static member classes over non static