Classi interne in java

Classe interna che significa
Come afferma il nome, una classe all’interno di un’altra classe viene chiamata Classe interna.
Le classi interne condividono una relazione speciale con la sua classe contenente in quanto ha accesso a tutti i membri della classe esterna(anche private quelli).
Questo perché una classe interna è anche un membro della classe esterna, proprio come altri campi e metodi.
Poiché una classe interna è una classe all’interno di un’altra classe, può anche essere definita una classe nidificata.
Tipi di classi interne
Una classe interna può essere dei seguenti tipi.

  1. Classe interna normale o regolare o nidificata(normalmente indicata come solo classe interna)
  2. Metodo Classe interna locale.
  3. Classe interna anonima.
  4. Classe nidificata statica

1. Classe interna nidificata
Questa sezione approfondirà tutti i dettagli di una classe interna. Per semplicità, considera le seguenti classi

class Outer { private String outerField = "Outer"; class Inner { private String innerField = "Inner"; }}

Qui Outer è la classe esterna e Inner è la classe interna che è contenuta all’interno di Outer.

Creazione di oggetti di classe interna
Una classe interna si trova all’interno di un’altra classe. La classe contenente è chiamata classe esterna. Pertanto, una classe interna non può esistere senza una classe esterna e lo stesso vale per il suo oggetto(o istanza).
Un oggetto di classe interna non può esistere senza un oggetto di classe esterna.
Ciò significa che per creare un’istanza di classe interna, è necessario disporre di un’istanza di classe esterna.
Pertanto, l’oggetto della classe interna può essere creato con il metodo indicato di seguito.

// first, create object of outer classOuter outerObject = new Outer();// create object of inner classInner innerObject = outerObject.new Inner();

Come risulta dall’esempio, per creare un oggetto di classe interna, è necessario un oggetto di classe esterna.
Esiste anche un metodo a mano corta per la creazione di oggetti di classe interna.

Inner innerObject = new Outer().new Inner();

Questo metodo richiede anche outer class object.
Solo Remember….An l’oggetto della classe interna non può essere creato senza un oggetto del suo contenente (o classe esterna).

Creazione di un oggetto di classe interna all’interno della classe esterna
L’esempio precedente presuppone che si stia istanziando una classe interna da qualche parte al di fuori della classe esterna.
Ma, nella maggior parte dei casi, è richiesto un oggetto di classe interna solo all’interno della classe esterna, poiché la classe esterna utilizza la classe interna.
Quindi, come creiamo un oggetto di classe interna dall’interno della classe esterna?
Considera la classe di esempio modificata di seguito.

class Outer { private String outerField = "Outer"; public void createInnerClassObject() { // create an object of inner class Inner innerObject = new Inner(); } class Inner { private String innerField = "Outer"; }}

Notare la linea Inner innerObject = new Inner();.
In precedenza è stato affermato che un oggetto di classe interna non può essere creato senza un oggetto di classe esterna, ma lo snippet di codice sopra lo sta facendo. Confuso !!!!
La sintassi precedente è valida perché è scritta all’interno di un metodo di classe esterna.
Quando questo codice è in esecuzione, è già presente un’istanza di classe esterna, che sta eseguendo il metodo.

Ricorda sempre, per creare (o accedere) un oggetto di classe interna, dovrebbe esserci un’istanza di classe esterna.

Per riassumere,

  1. Quando un oggetto di classe interna viene creato all’interno della classe esterna, può essere creato direttamente come Inner innerObject = new Inner();.
  2. Quando un oggetto di classe interna viene creato dall’esterno della classe esterna, deve essere creato come Inner innerObject = new Outer().new Inner();.

Quando vengono stampati oggetti di classe esterna e interna, di seguito è riportato l’output generato:

Istanza di classe esterna: Outer@659e0bfd
Istanza di classe interna : Outer Inner Inner@2a139a55

Riferimento all’istanza, ai campi e ai metodi della classe interna
Una classe interna è anche un membro della sua classe contenente come altri campi e metodi.
Quindi, può accedere ad altri campi e metodi di classe esterna nello stesso modo in cui altri campi e metodi accedono l’un l’altro, direttamente.
Questo vale quando si accede ai campi e ai metodi della classe esterna dalla classe interna.

Ma, quando si fa riferimento all’istanza della classe esterna, c’è una differenza. Per fare riferimento all’istanza corrente di una classe, viene utilizzata la parola chiave this.
In caso di classe interna, l’utilizzo di this all’interno della classe interna si riferisce all’istanza corrente della classe interna e non alla sua classe esterna.
Per fare riferimento all’istanza della classe esterna dalla classe interna, è necessario aggiungere il nome della classe alla parola chiave this.

Pertanto, per fare riferimento all’istanza della classe esterna dalla classe interna, utilizzare la sintassi Outer.this.
Fare riferimento sotto l’esempio per la comprensione.

class Outer { private String outerField = "Outer"; public void createInnerClassObject() { // create an object of inner class Inner innerObject = new Inner(); } class Inner { private String innerField = "Outer"; public innerClassMethod() { // access outer class field System.out.println("Outer field : " + outerField); // access inner class instance System.out.println("Inner instance : " + this); // access outer class instance System.out.println("Outer instance : " + Outer.this); } }}

Uscita

Campo esterno: Esterno
Istanza interna:
Istanza esterna:

2. Metodo Local Inner Class
Come suggerisce il nome, una classe definita all’interno di un metodo è una classe interna locale del metodo.
Sì, è possibile.
È possibile definire una classe all’interno di un metodo come mostrato di seguito.

// outer classclass Outer { // outer class method public void createClass() { // class inside a method class Inner { // inner class method public void innerMethod() { System.out.println("Method local inner class"); } } // inner class ends } // method ends}

Il codice precedente ha una classe esterna contenente un metodo.
Questo metodo definisce una classe che si trova all’interno del corpo del metodo, quindi chiamata classe interna locale del metodo.
Si noti che la classe interna ha anche una propria definizione di metodo.

Istanziare una classe interna locale del metodo
Il codice precedente dichiara una classe interna locale del metodo ma non crea alcun oggetto di classe interna.
Ora sorge la domanda, come creare un oggetto di metodo locale classe interna.
Poiché una classe interna locale del metodo è definita all’interno di un metodo, è visibile solo all’interno di quel metodo e il suo oggetto può anche essere creato solo all’interno di quel metodo.
Sotto il codice crea un oggetto di classe interna locale del metodo e chiama il suo metodo.

// outer classpublic class Outer { // outer class method public void createClass() { // class inside a method class Inner { // inner class method public void innerMethod() { System.out.println("Method local inner class method called"); } } // inner class ends // create inner class object Inner innerObject = new Inner(); // call inner class method innerObject.innerMethod(); } // outer class method ends // Main method public static void main(String args) { // create object of outer class Outer outerObject = new Outer(); // call outer class method outerObject.createClass(); }}

Quando viene eseguito il codice precedente, segue l’output

Metodo local inner class method chiamato

Questo mostra che quando viene chiamato il metodo outer class, crea un oggetto di inner class e chiama il metodo inner class.

Metodo Local Inner Class: Punti da ricordare
Istruzione che crea un oggetto del metodo local inner class dovrebbe essere scritto al di fuori del corpo della classe.
Quindi, la linea Inner innerObject = new Inner(); dovrebbe venire dopo la fine della classe locale.

  1. Una classe interna locale del metodo può essere istanziata solo all’interno del metodo in cui è dichiarata.
    Questo ha senso poiché una classe di metodo è visibile solo all’interno del metodo, quindi il suo oggetto può essere creato solo all’interno di quel metodo.
  2. Una classe interna locale del metodo non può accedere alle variabili locali del metodo in cui viene dichiarata.
    Se ha bisogno di accedervi, dovrebbero essere contrassegnati final.
    Questo è applicabile prima di java 8.
  3. Non è possibile accedere a una variabile locale del metodo all’interno di una classe interna locale del metodo e quindi riassegnarla. Questo sarà un errore del compilatore.
    Questo è applicabile da java 8 poiché le versioni precedenti a java 8 non consentono nemmeno di accedere a una variabile locale del metodo all’interno della classe interna.
  4. Una classe interna locale del metodo può accedere ai campi e ad altri metodi della classe a cui appartiene il metodo contenente la classe interna.
  5. Una classe interna locale del metodo può accedere ai campi static e ad altri metodi staticdella classe a cui appartiene il metodo contenente la classe interna solo quando il metodo contenente è static.

3. Classi interne anonime
Anonimo significa il cui nome non è noto. Nel contesto di java, una classe anonima è quella che non ha nome.
Il termine Classe anonima è applicabile solo alle classi interne poiché le classi esterne dovrebbero avere un nome.
Una classe anonima è una classe interna perché sarà sempre definita all’interno di un’altra classe.

Tipi di classe anonima in java
In realtà, una classe anonima è un’implementazione di una classe già esistente o un’interfaccia che è scritta da qualche altra parte ma è definita nuovamente all’interno di un’altra classe come richiesto.
Questo può sembrare confuso, ma gli esempi che seguono chiariranno il concetto.

In base al fatto che la classe anonima sia un’implementazione di una classe o di un’interfaccia, può appartenere alle seguenti due categorie

A. Sottoclasse di una classe
Iniziamo con un esempio prima

// Already existing classclass Website {public void printName() {System.out.println("No website till now");}}class SearchEngine { // Notice the syntax Website w = new WebSite() { public void printName() { System.out.println("Website is codippa.com"); } };}

Nell’esempio precedente, c’è una classe denominata Website che è già stata creata.
Un’altra classe SearchEngine ridefinisce questa classe, implementa il suo metodo e lo assegna a una variabile di riferimento che è dello stesso tipo della classe effettiva.
È anche possibile chiamare il metodo appena implementato utilizzando questa variabile di riferimento.

Ricorda che la classe anonima appena implementata è una sottoclasse della classe effettiva.
Segue il polimorfismo e il suo oggetto può essere passato ovunque sia previsto l’oggetto della classe Website.
Passare attraverso l’esempio seguente per l’illustrazione.

class Website { public void printName() { System.out.println("No website till now"); }}class SearchEngine { // Notice the syntax Website w = new WebSite() { public void printName() { System.out.println("Website is codippa.com"); } }; // Expects an instance of Website class public void getWebsite(Website web) { // call the method of Website class web.printName(); } // Main method public static void main(String args) { // create an object of this class SearchEngine obj = new SearchEngine(); // call its method and pass instance of Website class obj.getWebsite(obj.w); }}

Invece di pre-definire l’implementazione della classe Website, può essere definita dove richiesto, ovvero mentre si chiama il metodo getWebsite.
Quindi il metodo principale può essere modificato come

public static void main(String args) { SearchEngine obj = new SearchEngine(); // Notice the implementation of Website class as argument obj.getWebsite(new Website() { public void print() { System.out.println("Dynamic implementation"); } });}

L’implementazione di cui sopra non è assegnata a nessuna variabile di riferimento, non ha nome e quindi il nome Anonimo.

Non è necessario che entrambe le classi siano nello stesso file o pacchetto. Possono essere posizionati ovunque l’uno rispetto all’altro.

B. Implementatore di interfaccia
Una classe anonima può anche essere definita come l’implementatore di un’interfaccia.
In questo caso, definirà l’implementazione dei metodi dichiarati nell’interfaccia e può essere passata ovunque sia previsto l’oggetto dell’interfaccia.
Fare riferimento sotto l’esempio per renderlo chiaro.

interface WebInterface { // interface method declaration public void print();}class SearchEngine { // Notice the syntax WebInterface w = new WebInterface() { // Interface method implementation public void printName() { System.out.println("Website is codippa.com"); } }; // Expects an instance of WebInterface interface public void getWebsite(WebInterface web) { // call the method of WebInterface web.printName(); } // Main method public static void main(String args) { // create an object of this class SearchEngine obj = new SearchEngine(); // call its method and pass instance of WebInterface obj.getWebsite(obj.w); }}

Come prima, l’implementazione dell’interfaccia come classe anonima può essere creata dove richiesto come mostrato di seguito.

public static void main(String args) { SearchEngine obj = new SearchEngine(); // Notice the implementation of WebInterface as argument obj.getWebsite(new WebInterface() { public void print() { System.out.println("Dynamic implementation"); } });}
Si noti l’uso della parola chiave new prima del nome dell’interfaccia. Classe anonima è l’unico posto dove è possibile.

Polimorfismo nelle classi Anonime
Come affermato in precedenza, le classi anonime seguono il polimorfismo.
Poiché sono sottoclassi, dovrebbero seguire il polimorfismo. Questa sezione dettaglierà come.
Considera la classe sottostante.

class Metal { public void printThickness() { System.out.println("Thick enough"); }}class MetalDriver { // Anonymous class definition Metal metal = new Metal() { public void printThickness() { System.out.println("Thick enough"); } // new method public boolean hasLustre() { return false; } }; public void printMetalDetail(Metal m) { // call method present in actual class definition. No problem!!! m.printThickness(); // call newly defined method in Anonymous class. Compiler Error!!! m.hasLustre(); }}

Sopra il codice definisce un metallo di classe con un singolo metodo.
Questa classe viene implementata nuovamente in modo anonimo in un’altra classe MetalDriver in cui viene aggiunto un nuovo metodo alla sua definizione che non è presente nella classe effettiva.

Ora quando viene chiamato questo nuovo metodo, il compilatore si lamenta con un errore

Il metodo hasLustre() non è definito per il tipo Metal.

Questo perché la classe anonima è una sottoclasse mentre il riferimento è di classe effettiva(che è il genitore).
Il compilatore non è riuscito a trovare il nuovo metodo nella classe padre e segnala un errore.

Quindi, l’errore stabilisce due fatti:
(i) La classe anonima è una sottoclasse di classe effettiva e
(ii) Le definizioni di classe anonime seguono il polimorfismo.

Uso della classe anonima
Supponiamo di dover chiamare un metodo che accetta un argomento di un tipo che è un’interfaccia.
Ora, questa interfaccia appartiene ad una libreria esterna e non si dispone di una classe che implementa questa interfaccia.
Come chiamerai questo metodo. Se si passa null, esiste il rischio di eccezioni in fase di esecuzione.
Classe anonima in soccorso.
Ora puoi creare una classe anonima che implementa questa interfaccia e passarla sul metodo che fornisce l’implementazione dei suoi metodi secondo le tue esigenze.
Esempio seguente.

// Interface from external Libraryinterface External { public void interfaceMethod();}class CalledClass { // Method to called. Takes an argument of interface type public void toBeCalled(External e) { e.interfaceMethod(); }}

Il codice precedente ha un’interfaccia con un singolo metodo e una classe il cui metodo è necessario chiamare dal codice.

Il metodo di questa classe accetta un argomento di tipo interface ma non si dispone di una classe che implementa questa interfaccia.
Se si passa nullall’argomento del metodo, verrà immediatamente generato un java.lang.NullPointerException.
Dai un’occhiata a come puoi chiamare questo metodo usando la classe Anonima.

class CallingClass { // Main method public static void main(String args) { CalledClass obj = new CalledClass(); // call method using Anonymous class obj.toBeCalled(new External() { public void interfaceMethod() { // your code } }); }}

Si noti l’uso dell’implementazione dell’interfaccia anonima per chiamare il metodo.
Questo è il più grande vantaggio delle classi Anonime.
4. Classe nidificata statica
Una classe statica definita all’interno di un’altra classe è una classe nidificata statica. È definito proprio come una normale classe preceduta da una parola chiave statica.
Ricorda che non c’è nulla come classe statica, una classe nidificata statica è solo un membro statico della sua classe esterna.
Poiché è un membro statico, in seguito si applica a una classe nidificata statica.

  1. È possibile accedervi direttamente dalla classe esterna senza avere la sua istanza.
  2. Può accedere solo ai membri statici della sua classe esterna ma non alle sue variabili o metodi di istanza.

Esempio di classe nidificata statica

public class Outer { // static nested class static class Inner { public void innerMethod() { System.out.println("Method of static nested class"); } } public void outerMethod() { System.out.println("Method of outer class"); } public static void main(String args) { // access inner class directly Inner inner = new Inner(); // call nested class method inner.innerMethod(); }}

Come puoi vedere dall’esempio precedente, per accedere alla classe nidificata statica, non è richiesta un’istanza di classe esterna e vi si può accedere direttamente.
Si noti che l’oggetto della classe nidificata statica non può accedere ai membri non statici della classe esterna. Nell’esempio precedente, l’istanza di classe nidificata non può richiamare outerMethod della classe esterna.

Modifichiamo

  1. Quando viene compilata una classe contenente la classe interna, vengono generati 2 file di classe :
    uno per la classe esterna e uno per la classe interna.
    Esempio, Esterno.classe ed Esterno Inner Interno.classe per classe esterna esterna e classe interna interna rispettivamente..
  2. Il file di classe della classe interna non può essere eseguito direttamente utilizzando il comando java.
  3. Una normale classe interna non può avere static membri o metodi di dati.
  4. Una classe interna può avere un costruttore.
  5. Una classe locale di metodo può essere istanziata solo all’interno del metodo in cui è definita.
  6. Una classe locale del metodo definita nel metodo static può accedere solo ai membri static della classe che lo racchiude.
  7. Una classe anonima che implementa un’interfaccia, può implementare solo un’interfaccia rispetto alle normali classi che possono implementarne molte.
  8. Una classe anonima non può estendere una classe e implementare un’interfaccia allo stesso tempo che le classi normali possono.
  9. Le definizioni di classe anonime terminano con}; (Si noti il punto e virgola).
  10. Le classi anonime che sono definite come un argomento durante la chiamata di un metodo terminano con}); (Si noti il punto e virgola).
  11. Non è possibile chiamare un metodo sul riferimento di classe anonimo che non è presente nella classe effettiva.
  12. Una classe interna preceduta da static è nota come classe nidificata, non come classe interna.

Leave a Reply