Domanda

Qual è la differenza principale tra una classe interna e una classe nidificata statica in Java?La progettazione/implementazione gioca un ruolo nella scelta di uno di questi?

È stato utile?

Soluzione

Dal Tutorial Java:

Le classi annidate si dividono in due categorie:statico e non statico.Le classi nidificate dichiarate statiche sono semplicemente chiamate classi nidificate statiche.Le classi nidificate non statiche sono chiamate classi interne.

È possibile accedere alle classi nidificate statiche utilizzando il nome della classe che le racchiude:

OuterClass.StaticNestedClass

Ad esempio, per creare un oggetto per la classe nidificata statica, utilizzare questa sintassi:

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

Gli oggetti che sono istanze di una classe interna esistono all'interno di un'istanza della classe esterna.Consideriamo le seguenti classi:

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

Un'istanza di InnerClass può esistere solo all'interno di un'istanza di OuterClass e ha accesso diretto ai metodi e ai campi dell'istanza che la racchiude.

Per istanziare una classe interna, è necessario prima istanziare la classe esterna.Quindi, crea l'oggetto interno all'interno dell'oggetto esterno con questa sintassi:

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

Vedere: Tutorial Java - Classi nidificate

Per completezza, tieni presente che esiste anche una cosa come an classe interiore senza un'istanza che lo racchiude:

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

Qui, new A() { ... } è un classe interna definita in un contesto statico e non ha un'istanza di inclusione.

Altri suggerimenti

IL Il tutorial Java dice:

Terminologia:Le lezioni nidificate sono divise in due categorie:statico e non statico.Le lezioni nidificate che sono dichiarate statiche sono semplicemente chiamate lezioni nidificate statiche.Le lezioni nidificate non statiche sono chiamate classi interne.

Nel linguaggio comune, i termini "annidato" e "interno" sono usati in modo intercambiabile dalla maggior parte dei programmatori, ma userò il termine corretto "classe annidata" che copre sia interno che statico.

Le classi possono essere nidificate verso l'infinito, per esempio.la classe A può contenere la classe B che contiene la classe C che contiene la classe D, ecc.Tuttavia, più di un livello di nidificazione delle classi è raro, poiché generalmente si tratta di una cattiva progettazione.

Esistono tre motivi per cui potresti creare una classe nidificata:

  • organizzazione:a volte sembra più sensato ordinare una classe nello spazio dei nomi di un'altra classe, specialmente quando non verrà utilizzata in nessun altro contesto
  • accesso:le classi nidificate hanno un accesso speciale alle variabili/campi delle classi che le contengono (precisamente quali variabili/campi dipendono dal tipo di classe nidificata, interna o statica).
  • convenienza:dover creare un nuovo file per ogni nuovo tipo è fastidioso, ancora una volta, soprattutto quando il tipo verrà utilizzato solo in un contesto

Ci sono quattro tipi di classi annidate in Java.In breve, sono:

  • classe statica:dichiarato come membro statico di un'altra classe
  • classe interiore:dichiarato come membro di istanza di un'altra classe
  • classe interna locale:dichiarato all'interno di un metodo di istanza di un'altra classe
  • classe interna anonima:come una classe interna locale, ma scritta come un'espressione che restituisce un oggetto unico

Lasciami elaborare più in dettaglio.


Classi statiche

Le classi statiche sono il tipo più semplice da comprendere perché non hanno nulla a che fare con le istanze della classe che le contiene.

Una classe statica è una classe dichiarata come membro statico di un'altra classe.Proprio come gli altri membri statici, una classe di questo tipo è in realtà solo un supporto che utilizza la classe che la contiene come spazio dei nomi, per esempio. la classe Capra dichiarato come membro statico della classe Rinoceronte nel pacchetto Pizza è conosciuto con il nome pizza.Rhino.Capra.

package pizza;

public class Rhino {

    ...

    public static class Goat {
        ...
    }
}

Francamente, le classi statiche sono una caratteristica piuttosto inutile perché le classi sono già divise in spazi dei nomi dai pacchetti.L'unica vera ragione concepibile per creare una classe statica è che tale classe abbia accesso ai membri statici privati ​​della classe che la contiene, ma trovo che questa sia una giustificazione piuttosto debole per l'esistenza della funzionalità della classe statica.


Classi interiori

Una classe interna è una classe dichiarata come membro non statico di un'altra classe:

package pizza;

public class Rhino {

    public class Goat {
        ...
    }

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

Come con una classe statica, la classe interna è conosciuta come qualificata dal nome della classe che la contiene, pizza.Rhino.Capra, ma all'interno della classe che lo contiene può essere conosciuto con il suo semplice nome.Tuttavia, ogni istanza di una classe interna è legata a una particolare istanza della classe che la contiene:sopra il Capra creato nel Jerry, è implicitamente legato al Rinoceronte esempio Questo In Jerry.Altrimenti, creiamo l'associato Rinoceronte istanza esplicita quando istanziamo Capra:

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

(Nota che ti riferisci al tipo interno come just Capra nello strano nuovo sintassi:Java deduce il tipo contenitore da rinoceronte parte.E sì nuovo rinoceronte.Capra() avrebbe avuto più senso anche per me.)

Quindi cosa ci guadagna questo?Ebbene, l'istanza della classe interna ha accesso ai membri dell'istanza dell'istanza della classe che la contiene.Questi membri dell'istanza che li racchiudono sono indicati all'interno della classe interna attraverso solo i loro nomi semplici, no attraverso Questo (Questo nella classe interna si riferisce all'istanza della classe interna, non all'istanza della classe contenente associata):

public class Rhino {

    private String barry;

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

Nella classe interna, puoi fare riferimento a Questo della classe contenitore come Rhino.questo, e puoi usare Questo riferirsi ai suoi membri, per esempio.Rhino.questo.barry.


Classi interne locali

Una classe interna locale è una classe dichiarata nel corpo di un metodo.Tale classe è nota solo all'interno del metodo che la contiene, quindi è possibile istanziarla e consentire l'accesso ai suoi membri solo all'interno del metodo che la contiene.Il vantaggio è che un'istanza locale della classe interna è legata e può accedere alle variabili locali finali del metodo che la contiene.Quando l'istanza utilizza una versione locale finale del suo metodo contenitore, la variabile mantiene il valore che aveva al momento della creazione dell'istanza, anche se la variabile è uscita dall'ambito (questa è effettivamente la versione grezza e limitata delle chiusure di Java).

Poiché una classe interna locale non è né membro di una classe né di un pacchetto, non viene dichiarata con un livello di accesso.(Sii chiaro, tuttavia, che i suoi stessi membri hanno livelli di accesso come in una classe normale.)

Se una classe interna locale viene dichiarata in un metodo di istanza, un'istanza della classe interna è legata all'istanza mantenuta dal metodo che la contiene Questo al momento della creazione dell'istanza, quindi i membri dell'istanza della classe che la contiene sono accessibili come in una classe interna dell'istanza.Viene semplicemente istanziata una classe interna locale attraverso il suo nome, per esempio. classe interna locale Gatto è istanziato come nuovo gatto(), non nuovo this.Cat() come potresti aspettarti.


Classi interne anonime

Una classe interna anonima è un modo sintatticamente conveniente di scrivere una classe interna locale.Più comunemente, una classe interna locale viene istanziata al massimo una volta ogni volta che viene eseguito il metodo che la contiene.Sarebbe bello, quindi, se potessimo combinare la definizione della classe interna locale e la sua singola istanziazione in un'unica comoda forma sintattica, e sarebbe anche bello se non dovessimo pensare a un nome per la classe (meno inutili nomi contenuti nel codice, meglio è).Una classe interna anonima consente entrambe queste cose:

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

Questa è un'espressione che restituisce una nuova istanza di una classe senza nome che si estende NomeClasseGenitore.Non puoi fornire il tuo costruttore;piuttosto, ne viene fornito implicitamente uno che chiama semplicemente il super costruttore, quindi gli argomenti forniti devono adattarsi al super costruttore.(Se il genitore contiene più costruttori, quello "più semplice" viene chiamato "semplice" in quanto determinato da un insieme di regole piuttosto complesso che non vale la pena preoccuparsi di apprendere in dettaglio: presta solo attenzione a ciò che ti dicono NetBeans o Eclipse.)

In alternativa, è possibile specificare un'interfaccia da implementare:

new *InterfaceName*() {*members*}

Tale dichiarazione crea una nuova istanza di una classe senza nome che estende Object e implementa NomeInterfaccia.Ancora una volta, non puoi fornire il tuo costruttore;in questo caso, Java fornisce implicitamente un costruttore no-arg, do-nothing (quindi in questo caso non ci saranno mai argomenti del costruttore).

Anche se non puoi dare un costruttore a una classe interna anonima, puoi comunque eseguire qualsiasi configurazione desideri utilizzando un blocco inizializzatore (un blocco {} posizionato all'esterno di qualsiasi metodo).

Sii chiaro che una classe interna anonima è semplicemente un modo meno flessibile di creare una classe interna locale con un'istanza.Se si desidera una classe interna locale che implementi più interfacce o che implementi interfacce estendendo alcune classi diverse da Oggetto o che specifica il proprio costruttore, sei bloccato nel creare una classe interna locale con nome regolare.

Non credo che la vera differenza sia diventata chiara nelle risposte di cui sopra.

Innanzitutto per capire bene i termini:

  • Una classe nidificata è una classe contenuta in un'altra classe a livello di codice sorgente.
  • È statico se lo dichiari con il file statico modificatore.
  • Una classe nidificata non statica è chiamata classe interna.(Resto con la classe nidificata non statica.)

La risposta di Martin è giusta finora.Tuttavia la vera domanda è:Qual è lo scopo di dichiarare statica una classe nidificata o no?

Usate classi nidificate statiche se vuoi semplicemente tenere insieme le tue classi se appartengono insieme per via topica o se la classe nidificata viene utilizzata esclusivamente nella classe che la racchiude.Non esiste alcuna differenza semantica tra una classe nidificata statica e ogni altra classe.

Classi annidate non statiche sono una bestia diversa.Similmente alle classi interne anonime, tali classi nidificate sono in realtà delle chiusure.Ciò significa che catturano l'ambito circostante e l'istanza che li racchiude e li rendono accessibili.Forse un esempio lo chiarirà.Vedi questo stub di un contenitore:

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

In questo caso vuoi avere un riferimento da un elemento figlio al contenitore padre.Utilizzando una classe nidificata non statica, funziona senza alcun lavoro.È possibile accedere all'istanza di inclusione di Container con la sintassi Container.this.

Di seguito ulteriori spiegazioni fondamentali:

Se guardi i bytecode Java generati dal compilatore per una classe nidificata (non statica), potrebbe diventare ancora più chiaro:

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

Come puoi vedere il compilatore crea un campo nascosto Container this$0.Questo è impostato nel costruttore che ha un parametro aggiuntivo di tipo Container per specificare l'istanza di inclusione.Non puoi vedere questo parametro nell'origine ma il compilatore lo genera implicitamente per una classe nidificata.

L'esempio di Martino

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

verrebbe quindi compilato in una chiamata di qualcosa come (in bytecode)

new InnerClass(outerObject)

Per amor di completezza:

Una classe anonima È un esempio perfetto di una classe nidificata non statica a cui semplicemente non è associato alcun nome e non è possibile fare riferimento in seguito.

Penso che nessuna delle risposte di cui sopra ti spieghi la reale differenza tra una classe nidificata e una classe nidificata statica in termini di progettazione dell'applicazione:

Panoramica

Una classe annidata potrebbe essere non statico o statico e in ogni caso è una classe definita all'interno di un'altra classe. Una classe nidificata dovrebbe esistere solo per servire la classe che la racchiude, se una classe nidificata è utile ad altre classi (non solo a quelle di inclusione), dovrebbe essere dichiarata come classe di livello superiore.

Differenza

Classe annidata non statica :è implicitamente associato all'istanza che lo contiene, ciò significa che è possibile invocare metodi e accedere alle variabili dell'istanza che lo contiene.Un uso comune di una classe nidificata non statica è definire una classe Adapter.

Classe nidificata statica :non può accedere all'istanza della classe che la racchiude e invocare metodi su di essa, quindi dovrebbe essere utilizzata quando la classe nidificata non richiede l'accesso a un'istanza della classe che la racchiude.Un uso comune della classe nidificata statica è implementare un componente dell'oggetto esterno.

Conclusione

Quindi la differenza principale tra i due dal punto di vista del design è: la classe nidificata non statica può accedere all'istanza della classe contenitore, mentre la classe statica no.

In termini semplici abbiamo bisogno di classi nidificate principalmente perché Java non fornisce chiusure.

Le classi nidificate sono classi definite all'interno del corpo di un'altra classe che le racchiude.Sono di due tipi: statici e non statici.

Sono trattati come membri della classe che li racchiude, quindi puoi specificare uno qualsiasi dei quattro specificatori di accesso: private, package, protected, public.Non possiamo permetterci questo lusso con le classi di massimo livello, che possono solo essere dichiarate public o pacchetto privato.

Le classi interne, ovvero le classi non stack, hanno accesso ad altri membri della classe superiore, anche se sono dichiarate private mentre le classi nidificate statiche non hanno accesso ad altri membri della classe superiore.

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

Inner1 è la nostra classe interiore statica e Inner2 è la nostra classe interiore che non è statica.La differenza fondamentale tra loro è che non puoi creare un file Inner2 istanza senza un Esterno dove puoi creare un file Inner1 oggetto in modo indipendente.

Quando utilizzeresti la classe Inner?

Pensa a una situazione in cui Class A E Class B sono correlati, Class B ha bisogno di accedere Class A membri e Class B è correlato solo a Class A.Le classi interiori entrano in scena.

Per creare un'istanza della classe interna, devi creare un'istanza della tua classe esterna.

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

O

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

Quando utilizzeresti la classe interna statica?

Definiresti una classe interna statica quando sai che non ha alcuna relazione con l'istanza della classe/classe superiore che la racchiude.Se la tua classe interna non utilizza metodi o campi della classe esterna, è solo uno spreco di spazio, quindi rendila statica.

Ad esempio, per creare un oggetto per la classe nidificata statica, utilizzare questa sintassi:

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

Il vantaggio di una classe nidificata statica è che non ha bisogno di un oggetto della classe contenente/classe principale per funzionare.Ciò può aiutarti a ridurre il numero di oggetti creati dall'applicazione in fase di runtime.

Penso che la convenzione generalmente seguita sia questa:

  • classe statica all'interno di una classe di livello superiore è a classe annidata
  • classe non statica all'interno di una classe di livello superiore è a classe interiore, che ha ulteriormente altre due forme:
    • classe locale - classi con nome dichiarate all'interno di un blocco come un metodo o un corpo del costruttore
    • classe anonima - classi senza nome le cui istanze vengono create in espressioni e istruzioni

Tuttavia, pochi altri punta a ricordare Sono:

  • Le classi di primo livello e la classe nidificata statica sono semanticamente identiche, tranne per il fatto che in caso di classe nidificata statica può fare riferimento statico a campi/metodi statici privati ​​della sua classe esterna [genitore] e viceversa.

  • Le classi interne hanno accesso alle variabili di istanza dell'istanza che la racchiude della classe [genitore] esterna.Tuttavia, non tutte le classi interne hanno istanze di inclusione, ad esempio le classi interne in contesti statici, come una classe anonima utilizzata in un blocco inizializzatore statico, non ne hanno.

  • La classe anonima per impostazione predefinita estende la classe genitore o implementa l'interfaccia genitore e non sono presenti ulteriori clausole per estendere qualsiasi altra classe o implementare altre interfacce.COSÌ,

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

Sento che la domanda più grande che rimane aperta è quale usare e quando?Beh, dipende principalmente dallo scenario con cui hai a che fare, ma leggere la risposta data da @jrudolph può aiutarti a prendere una decisione.

Ecco le principali differenze e somiglianze tra la classe interna Java e la classe nidificata statica.

Spero che sia d'aiuto!

Classe interiore

  • Può accedere alla classe esterna sia istanza che statico metodi e campi
  • Associato all'istanza della classe che racchiude quindi per istanziarlo è necessaria prima un'istanza della classe esterna (nota nuovo luogo della parola chiave):

    Outerclass.InnerClass innerObject = outerObject.new Innerclass();
    
  • Non può definire qualsiasi membri statici si

  • Non può Avere Classe O Interfaccia dichiarazione

Classe nidificata statica

  • Non poter accedere classe esterna esempio metodi o campi

  • Non associato ad alcuna istanza della classe di inclusione Quindi per istanziarlo:

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

Analogie

  • Entrambi Classi interiori può accedere anche campi e metodi privati Di classe esterna
  • Anche il Classe esterna avere accesso a campi e metodi privati Di classi interiori
  • Entrambe le classi possono avere un modificatore di accesso privato, protetto o pubblico

Perché utilizzare le classi nidificate?

Secondo la documentazione Oracle ci sono diversi motivi (documentazione completa):

  • È un modo per raggruppare logicamente le classi che vengono utilizzate solo in un posto: Se una classe è utile solo a un'altra classe, allora è logico incorporarla in quella classe e tenerle insieme.Nidificare tali "classi helper" rende il loro pacchetto più snello.

  • Aumenta l'incapsulamento: Consideriamo due classi di primo livello, A e B, dove B ha bisogno di accedere ai membri di A che altrimenti verrebbero dichiarati privati.Nascondendo la classe B all'interno della classe A, i membri di A possono essere dichiarati privati ​​e B può accedervi.Inoltre, B stesso può essere nascosto al mondo esterno.

  • Può portare a un codice più leggibile e gestibile: Nidificare piccole classi all'interno di classi di livello superiore posiziona il codice più vicino a dove viene utilizzato.

Classe nidificata:classe nella classe

Tipi:

  1. Classe nidificata statica
  2. Classe nidificata non statica [classe interna]

Differenza:

Classe nidificata non statica [classe interna]

Nella classe nidificata non statica, l'oggetto della classe interna esiste all'interno dell'oggetto della classe esterna.In modo che il membro dati della classe esterna sia accessibile alla classe interna.Quindi per creare un oggetto della classe interna dobbiamo prima creare un oggetto della classe esterna.

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

Classe nidificata statica

Nella classe nidificata statica l'oggetto della classe interna non ha bisogno dell'oggetto della classe esterna, perché la parola "statico" indica che non è necessario creare un oggetto.

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

Se vuoi accedere a x, scrivi il seguente metodo inside

  outerclass.nestedclass.x;  i.e. System.out.prinltn( outerclass.nestedclass.x);

L'istanza della classe interna viene creata quando viene creata l'istanza della classe esterna.Pertanto i membri e i metodi della classe interna hanno accesso ai membri e ai metodi dell'istanza (oggetto) della classe esterna.Quando l'istanza della classe esterna esce dall'ambito, anche le istanze della classe interna cessano di esistere.

La classe nidificata statica non ha un'istanza concreta.Viene semplicemente caricato quando viene utilizzato per la prima volta (proprio come i metodi statici).È un'entità completamente indipendente, i cui metodi e variabili non hanno alcun accesso alle istanze della classe esterna.

Le classi nidificate statiche non sono accoppiate con l'oggetto esterno, sono più veloci e non occupano memoria heap/stack, perché non è necessario creare un'istanza di tale classe.Pertanto la regola pratica è provare a definire una classe nidificata statica, con un ambito quanto più limitato possibile (privato >= classe >= protetta >= pubblica), quindi convertirla in classe interna (rimuovendo l'identificatore "statico") e allentare l'ambito, se è davvero necessario.

C'è una sottigliezza nell'uso delle classi statiche nidificate che potrebbe essere utile in determinate situazioni.

Mentre gli attributi statici vengono istanziati prima che la classe venga istanziata tramite il suo costruttore, gli attributi statici all'interno delle classi statiche nidificate non sembrano essere istanziati fino a quando il costruttore della classe non viene invocato, o almeno non fino a quando gli attributi non sono stati fatti riferimento Sono contrassegnati come "finale".

Considera questo esempio:

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");
    }
}

Anche se "nested" e "innerItem" sono entrambi dichiarati come "static final".L'impostazione di nidificata.innitem non si verifica fino a quando la classe non è stata istanziata (o almeno non fino a quando l'articolo statico nidificato è stato riferito per la prima Sopra.Lo stesso non vale per "esterno".

Almeno questo è quello che vedo in Java 6.0.

Nel caso della creazione di istanza, l'istanza di classe interna non statica viene creata con il riferimento dell'oggetto della classe esterna in cui è definita.Ciò significa che ha un'istanza inclusi.Ma l'istanza della classe interna statica viene creata con il riferimento della classe esterna, non con il riferimento dell'oggetto della classe esterna.Ciò significa che non ha incluso istanza.

Per esempio:

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

Non penso che ci sia molto da aggiungere qui, la maggior parte delle risposte spiega perfettamente le differenze tra classi nidificate statiche e classi interne.Tuttavia, considera il seguente problema quando utilizzi classi nidificate rispetto a classi interne.Come menzionato in un paio di risposte, le classi interne non possono essere istanziate senza un'istanza della classe che le racchiude, il che significa che lo sono PRESA UN puntatore all'istanza della classe di inclusione che può portare a un overflow di memoria o a un'eccezione di overflow dello stack dovuta al fatto che il GC non sarà in grado di eseguire la garbage collection delle classi di inclusione anche se non vengono più utilizzate.Per chiarire questo, controlla il seguente codice:

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();

}

Se rimuovi il commento su // inner = null; Il programma sarà messo in uscita "Sono distrutto!", ma mantenerlo commentato non lo farà.
Il motivo è che all'istanza interna bianca viene ancora fatto riferimento. GC non può raccoglierla e poiché fa riferimento (ha un puntatore a) all'istanza esterna, anch'essa non viene raccolta.Avere abbastanza di questi oggetti nel tuo progetto può esaurire la memoria.
Rispetto alle classi interne statiche che non hanno un punto per l'istanza della classe interna perché non è correlata all'istanza ma alla classe.Il programma sopra può stampare "Sono distrutto!" se rendi la classe Inner statica e istanziata con Outer.Inner i = new Outer.Inner();

I termini sono usati in modo intercambiabile.Se vuoi essere davvero pedante al riguardo, allora tu Potevo definire "classe nidificata" per fare riferimento a una classe interna statica, che non ha alcuna istanza che la racchiuda.Nel codice, potresti avere qualcosa del genere:

public class Outer {
    public class Inner {}

    public static class Nested {}
}

Tuttavia non è una definizione ampiamente accettata.

La classe nidificata è un termine molto generale:ogni classe che non è di livello superiore è una classe nidificata.Una classe interna è una classe annidata non statica.Joseph Darcy ha scritto una spiegazione molto bella a riguardo Classi nidificate, interne, membro e di primo livello.

Uhm...una classe interna È una classe nidificata...intendi classe anonima e classe interna?

Modificare:Se davvero intendevi interiore vs anonimo...una classe interna è solo una classe definita all'interno di una classe come:

public class A {
    public class B {
    }
}

Mentre una classe anonima è un'estensione di una classe definita in modo anonimo, quindi non viene definita alcuna classe effettiva, come in:

public class A {
}

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

Ulteriore modifica:

Wikipedia afferma che c'è una differenza in Java, ma lavoro con Java da 8 anni, ed è la prima volta che sento una distinzione del genere...per non parlare del fatto che non ci sono riferimenti a sostegno di quanto affermato...in conclusione, una classe interna è una classe definita all'interno di una classe (statica o meno) e nidificata è solo un altro termine per indicare la stessa cosa.

C'è una sottile differenza tra la classe nidificata statica e non statica...fondamentalmente le classi interne non statiche hanno accesso implicito ai campi di istanza e ai metodi della classe che le racchiude (quindi non possono essere costruite in un contesto statico, sarebbe un errore del compilatore).Le classi nidificate statiche, d'altro canto, non hanno accesso implicito ai campi e ai metodi di istanza e POSSONO essere costruite in un contesto statico.

Targeting per studenti alle prime armi con Java e/o classi nidificate

Le classi nidificate possono essere:
1.Classi nidificate statiche.
2.Classi nidificate non statiche.(conosciuto anche come Classi interiori) =>Per favore ricordalo


1.Classi interne
Esempio:

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


Le classi interne sono sottoinsiemi di classi annidate:

  • la classe interna è un tipo specifico di classe nidificata
  • le classi interne sono sottoinsiemi di classi annidate
  • Puoi dire che un anche la classe interna è una classe nidificata, ma puoi farlo NON diciamo che una classe nidificata è anche una classe interna.

Specialità della classe interna:

  • ha un'istanza di una classe interna accesso a tutti dei membri della classe esterna, anche quelli contrassegnati come “privati”


2.Classi nidificate statiche:
Esempio:

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

Caso 1: istanziare una classe nidificata statica da una classe che non lo racchiude

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

Caso 2: istanziare una classe nidificata statica da una classe che la racchiude

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

}

Specialità delle classi statiche:

  • La classe interna statica avrebbe accesso solo ai membri statici della classe esterna e non avrebbe accesso ai membri non statici.

Conclusione:
Domanda: Qual è la differenza principale tra una classe interna e una classe nidificata statica in Java?
Risposta: basta esaminare le specifiche di ciascuna classe menzionata sopra.

Classe interiore E classe statica annidata in Java entrambe sono classi dichiarate all'interno di un'altra classe, nota come classe di primo livello in Java.Nella terminologia Java, se dichiari statica una classe nidificata, verrà chiamata classe statica nidificata in Java mentre le classi nidificate non statiche vengono semplicemente chiamate classe interna.

Cos'è la classe interna in Java?

Qualsiasi classe che non sia di livello superiore o dichiarata all'interno di un'altra classe è nota come classe nidificata e, tra quelle classi nidificate, le classi dichiarate non statiche sono note come classe interna in Java.ci sono tre tipi di classe interna in Java:

1) Classe interna locale: viene dichiarata all'interno di un blocco di codice o metodo.
2) Classe interna anonima: è una classe che non ha un nome a cui fare riferimento ed è inizializzata nello stesso posto in cui viene creata.
3) Membro della classe interna: viene dichiarato come membro non statico della classe esterna.

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");
        }
    }
}

Cos'è la classe statica annidata in Java?

La classe statica nidificata è un'altra classe dichiarata all'interno di una classe come membro e resa statica.La classe statica nidificata viene dichiarata anche come membro della classe esterna e può essere resa privata, pubblica o protetta come qualsiasi altro membro.Uno dei principali vantaggi della classe statica nidificata rispetto alla classe interna è che l'istanza della classe statica nidificata non è collegata ad alcuna istanza che la racchiude della classe esterna. Inoltre, non è necessaria alcuna istanza della classe Outer per creare un'istanza della classe statica annidata in Java.

1) Può accedere membri dati statici di classe esterna compreso il privato.
2) La classe nidificata statica non può accedere membro dati non statico (istanza). O metodo.

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");
        }
    }
}

Rif: Classe interna e classe statica annidata in Java con esempio

Penso che le persone qui dovrebbero notare a Poster che:La classe Nest statica è solo la prima classe interna.Per esempio:

 public static class A {} //ERROR

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

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

 }

Quindi, riassumendo, la classe statica non dipende dalla classe che contiene.Quindi, non possono nella classe normale.(perché la classe normale necessita di un'istanza).

Quando dichiariamo una classe membro statica all'interno di una classe, è nota come classe nidificata di livello superiore o classe nidificata statica.Può essere dimostrato come di seguito:

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());
    }
}

Quando dichiariamo una classe membro non statica all'interno di una classe, questa è nota come classe interna.La classe interna può essere dimostrata come di seguito:

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

Quello che segue è un esempio di static nested class E 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);
     }

}

TestClasseEsterna:

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()); 

    }

}

Penso che nessuna delle risposte di cui sopra ti fornisca un esempio reale della differenza tra una classe nidificata e una classe nidificata statica in termini di progettazione dell'applicazione.E la differenza principale tra la classe nidificata statica e la classe interna è la possibilità di accedere al campo dell'istanza della classe esterna.

Diamo uno sguardo ai due esempi seguenti.

Classe nido statico:Un buon esempio di utilizzo di classi nidificate statiche è il pattern di creazione (https://dzone.com/articles/design-patterns-the-builder-pattern).

Per BankAccount utilizziamo una classe nidificata statica, principalmente perché

  1. L'istanza statica della classe nidificata potrebbe essere creata prima della classe esterna.

  2. Nel modello builder, il builder è una classe helper utilizzata per creare BankAccount.

  3. BankAccount.Builder è associato solo a BankAccount.Nessun'altra classe è correlata a BankAccount.Builder.quindi è meglio organizzarli insieme senza usare convenzioni sui nomi.
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;
        }
    }
}

Classe interna:Un uso comune delle classi interne è definire un gestore di eventi.https://docs.oracle.com/javase/tutorial/uiswing/events/generalrules.html

Per MyClass utilizziamo la classe interna, principalmente perché:

  1. La classe interna MyAdapter deve accedere al membro della classe esterna.

  2. Nell'esempio MyAdapter è associato solo a MyClass.Nessun'altra classe è correlata a MyAdapter.quindi è meglio organizzarli insieme senza utilizzare una convenzione sui nomi

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

Prima di tutto Non esiste una classe chiamata Classe statica. L'uso del modificatore Statico con la classe interna (chiamata Classe nidificata) dice che è un membro statico della Classe esterna, il che significa che possiamo accedervi come con altri membri statici e senza averne alcuno istanza della classe esterna.(Che è il vantaggio della statica originariamente.)

La differenza tra l'utilizzo della classe nidificata e della normale classe interna è:

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

Per prima cosa possiamo creare un'istanza di Outerclass, quindi possiamo accedere a Inner.

Ma se la classe è nidificata, la sintassi è:

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

Che utilizza la sintassi statica come normale implementazione della parola chiave statica.

Il linguaggio di programmazione Java consente di definire una classe all'interno di un'altra classe.Tale classe è chiamata classe nidificata ed è illustrata qui:

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

Le classi annidate si dividono in due categorie:statico e non statico.Le classi nidificate dichiarate statiche sono chiamate classi nidificate statiche.Le classi nidificate non statiche sono chiamate classi interne.Una cosa che dovremmo tenere a mente è che le classi nidificate non statiche (classi interne) hanno accesso ad altri membri della classe che le racchiude, anche se sono dichiarate private.Le classi nidificate statiche hanno accesso solo agli altri membri della classe che li racchiude se questi sono statici.Non può accedere ai membri non statici della classe esterna.Come con i metodi e le variabili della classe, una classe nidificata statica è associata alla sua classe esterna.Ad esempio, per creare un oggetto per la classe nidificata statica, utilizzare questa sintassi:

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

Per istanziare una classe interna, è necessario prima istanziare la classe esterna.Quindi, crea l'oggetto interno all'interno dell'oggetto esterno con questa sintassi:

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

Perché usiamo le classi nidificate

  1. È un modo per raggruppare logicamente le classi che vengono utilizzate solo in un posto.
  2. Aumenta l'incapsulamento.
  3. Può portare a un codice più leggibile e gestibile.

Fonte: I tutorial Java™ - Classi nidificate

La differenza è che una dichiarazione di classe annidata che è anche statica può essere istanziata all'esterno della classe che la racchiude.

Quando hai una dichiarazione di classe nidificata, lo è non statico, noto anche come an classe interiore, Java non ti consentirà di crearne un'istanza se non tramite la classe che lo racchiude.L'oggetto creato dalla classe interna è collegato all'oggetto creato dalla classe esterna, quindi la classe interna può fare riferimento ai campi di quella esterna.

Ma se è statico, allora il collegamento non esiste, non è possibile accedere ai campi esterni (se non tramite un riferimento ordinario come qualsiasi altro oggetto) e quindi è possibile istanziare da sola la classe nidificata.

Ho illustrato vari possibili scenari corretti ed errori che possono verificarsi nel codice 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);
                        }*/
                    //}
                }
    }
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top