Innere Klassen in Java
Innere Klasse Bedeutung
Wie der Name schon sagt, wird eine Klasse in einer anderen Klasse als Innere Klasse bezeichnet.
Innere Klassen haben eine besondere Beziehung zu ihrer enthaltenden Klasse, da sie Zugriff auf alle Mitglieder der äußeren Klasse hat (sogar private
).
Dies liegt daran, dass eine innere Klasse ebenso wie andere Felder und Methoden Mitglied der äußeren Klasse ist.
Da eine innere Klasse eine Klasse innerhalb einer anderen Klasse ist, kann sie auch als verschachtelte Klasse bezeichnet werden.
Typen innerer Klassen
Eine innere Klasse kann von folgenden Typen sein.
- Normale oder reguläre oder verschachtelte innere Klasse (normalerweise nur als innere Klasse bezeichnet)
- Methode Lokale Innere Klasse.
- Anonyme Innere Klasse.
- Statische verschachtelte Klasse
1. Verschachtelte innere Klasse
In diesem Abschnitt werden alle Details einer inneren Klasse behandelt. Betrachten Sie der Einfachheit halber die folgenden Klassen
class Outer { private String outerField = "Outer"; class Inner { private String innerField = "Inner"; }}
Hier ist Outer die äußere Klasse und Inner ist die innere Klasse, die in Outer enthalten ist.
Objekt der inneren Klasse erstellen
Eine innere Klasse befindet sich in einer anderen Klasse. Die enthaltende Klasse wird äußere Klasse genannt. Daher kann eine innere Klasse nicht ohne äußere Klasse existieren, und dasselbe gilt für ihr Objekt (oder ihre Instanz).
Ein Objekt der inneren Klasse kann nicht ohne ein Objekt der äußeren Klasse existieren.
Dies bedeutet, dass Sie zum Erstellen einer Instanz der inneren Klasse eine Instanz der äußeren Klasse benötigen.
Somit kann ein Objekt der inneren Klasse mit der unten angegebenen Methode erstellt werden.
// first, create object of outer classOuter outerObject = new Outer();// create object of inner classInner innerObject = outerObject.new Inner();
Wie aus dem Beispiel hervorgeht, ist zum Erstellen eines Objekts der inneren Klasse ein Objekt der äußeren Klasse erforderlich.
Es gibt auch eine Kurzhandmethode zum Erstellen eines inneren Klassenobjekts.
Inner innerObject = new Outer().new Inner();
Diese Methode erfordert auch outer class object .
Nur Remember….An objekt der inneren Klasse kann nicht ohne ein Objekt seiner enthaltenden (oder äußeren Klasse) erstellt werden.
Erstellen eines inneren Klassenobjekts innerhalb der äußeren Klasse
Im vorherigen Beispiel wird davon ausgegangen, dass Sie die innere Klasse von irgendwo außerhalb der äußeren Klasse instanziieren.
In den meisten Fällen ist jedoch ein Objekt der inneren Klasse nur innerhalb der äußeren Klasse erforderlich, da die äußere Klasse die innere Klasse verwendet.
Wie erstellen wir also ein Objekt der inneren Klasse aus der inneren äußeren Klasse?
Betrachten Sie die modifizierte Beispielklasse unten.
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"; }}
Beachten Sie die Zeile Inner innerObject = new Inner();
.
Zuvor wurde angegeben, dass ein Objekt der inneren Klasse nicht ohne ein Objekt der äußeren Klasse erstellt werden kann, aber das obige Code-Snippet tut es. Verwirrt !!!!
Die obige Syntax ist gültig, da sie in einer Methode der äußeren Klasse geschrieben ist.
Wenn dieser Code ausgeführt wird, ist bereits eine Instanz der äußeren Klasse vorhanden, die die Methode ausführt.
Denken Sie immer daran, um ein Objekt der inneren Klasse zu erstellen (oder darauf zuzugreifen), sollte es eine Instanz der äußeren Klasse geben.
Zusammenfassen,
- Wenn ein Objekt der inneren Klasse innerhalb der äußeren Klasse erstellt wird, kann es direkt als
Inner innerObject = new Inner();
erstellt werden. - Wenn ein Objekt der inneren Klasse von außerhalb der äußeren Klasse erstellt wird, muss es als
Inner innerObject = new Outer().new Inner();
erstellt werden.
Wenn Objekte der äußeren und inneren Klasse gedruckt werden, folgt die generierte Ausgabe:
Instanz der äußeren Klasse: Outer@659e0bfd
Instanz der inneren Klasse : Outer$Inner@2a139a55
Referenzierung der äußeren Klasseninstanz, Felder und Methoden aus der inneren Klasse
Eine innere Klasse ist wie andere Felder und Methoden auch Mitglied ihrer enthaltenden Klasse.
Somit kann es auf andere Felder und Methoden der äußeren Klasse zugreifen, genauso wie andere Felder und Methoden direkt aufeinander zugreifen.
Dies gilt für den Zugriff auf Felder und Methoden der äußeren Klasse aus der inneren Klasse.
Wenn Sie jedoch auf die Instanz der äußeren Klasse verweisen, gibt es einen Unterschied. Um auf die aktuelle Instanz einer Klasse zu verweisen, wird das Schlüsselwort this
verwendet.
Im Falle einer inneren Klasse bezieht sich die Verwendung von this
innerhalb der inneren Klasse auf die aktuelle Instanz der inneren Klasse und nicht auf deren äußere Klasse.
Um die Instanz der äußeren Klasse von der inneren Klasse zu referenzieren, müssen wir dem Schlüsselwort this
den Klassennamen hinzufügen.
Verwenden Sie daher die Syntax Outer.this
, um auf die Instanz der äußeren Klasse von der inneren Klasse zu verweisen.
Siehe unten beispiel für verständnis.
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); } }}
Ausgabe
Äußeres Feld: Äußeres
Innere Instanz:
Äußere Instanz :
2. Methode Lokale innere Klasse
Wie der Name schon sagt, ist eine in einer Methode definierte Klasse eine Methode Lokale innere Klasse.
Ja, das ist möglich.
Sie können eine Klasse innerhalb einer Methode definieren, wie unten gezeigt.
// 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}
Der obige Code hat eine Klasse Outer, die eine Methode enthält.
Diese Methode definiert eine Klasse, die sich innerhalb des Methodenkörpers befindet und daher method local inner class genannt wird.
Beachten Sie, dass die innere Klasse auch eine eigene Methodendefinition hat.
Instanziieren einer Methode lokale innere Klasse
Der vorhergehende Code deklariert eine Methode lokale innere Klasse, erstellt jedoch kein Objekt der inneren Klasse.
Nun stellt sich die Frage, wie man ein Objekt der lokalen inneren Klasse erstellt.
Da eine methodenlokale innere Klasse innerhalb einer Methode definiert ist, ist sie nur innerhalb dieser Methode sichtbar und ihr Objekt kann auch nur innerhalb dieser Methode erstellt werden.
Der folgende Code erstellt ein Objekt der lokalen inneren Klasse method und ruft seine Methode auf.
// 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(); }}
Wenn der obige Code ausgeführt wird, folgt die Ausgabe
Methode lokale innere Klassenmethode mit dem Namen
Dies zeigt, dass beim Aufruf der äußeren Klassenmethode ein Objekt der inneren Klasse erstellt und die innere Klassenmethode aufgerufen wird.
Method Local Inner Class : Verweist auf die
Anweisung, die ein Objekt der Methode local inner class erstellt, sollte außerhalb des Klassenkörpers geschrieben werden.
Daher sollte die Zeile Inner innerObject = new Inner();
nach dem Ende der lokalen Klasse stehen.
- Eine lokale innere Methodenklasse kann nur innerhalb der Methode instanziiert werden, in der sie deklariert ist.
Dies ist sinnvoll, da eine Methodenklasse nur innerhalb der Methode sichtbar ist und daher ihr Objekt nur innerhalb dieser Methode erstellt werden kann. - Eine lokale innere Methodenklasse kann nicht auf die lokalen Variablen der Methode zugreifen, in der sie deklariert ist.
Wenn es auf sie zugreifen muss, sollten sie mitfinal
gekennzeichnet sein.
Dies gilt vor Java 8. - Sie können nicht auf eine lokale Methodenvariable innerhalb einer lokalen inneren Methodenklasse zugreifen und sie dann neu zuweisen. Dies wird ein Compilerfehler sein.
Dies gilt ab Java 8, da Versionen vor Java 8 nicht einmal den Zugriff auf eine lokale Methodenvariable innerhalb der inneren Klasse ermöglichen. - Eine Methode mit innerer Klasse kann auf die Felder und andere Methoden der Klasse zugreifen, zu der die Methode mit innerer Klasse gehört.
- Eine Methode mit innerer Klasse kann nur dann auf die
static
-Felder und anderestatic
-Methoden der Klasse zugreifen, zu der die Methode mit innerer Klasse gehört, wenn die enthaltende Methodestatic
ist.
3. Anonyme Innere Klassen
Anonyme Mittel, deren Name nicht bekannt ist. Im Kontext von Java ist eine anonyme Klasse eine, die keinen Namen hat.
Der Begriff Anonyme Klasse gilt nur für innere Klassen, da äußere Klassen einen Namen haben sollten.
Eine anonyme Klasse ist eine innere Klasse, da sie immer innerhalb einer anderen Klasse definiert wird.
Typen anonymer Klassen in Java
Tatsächlich ist eine anonyme Klasse eine Implementierung einer bereits vorhandenen Klasse oder einer Schnittstelle, die an einer anderen Stelle geschrieben wurde, aber bei Bedarf innerhalb einer anderen Klasse erneut definiert wird.
Das mag verwirrend klingen, aber die folgenden Beispiele werden das Konzept verdeutlichen.
Basierend darauf, ob die anonyme Klasse eine Implementierung einer Klasse oder einer Schnittstelle ist, kann sie zu den folgenden zwei Kategorien gehören
A. Unterklasse einer Klasse
Beginnen wir mit einem Beispiel zuerst
// 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"); } };}
Im obigen Beispiel gibt es eine Klasse namens Website, die bereits erstellt wurde.
Eine andere Klasse SearchEngine definiert diese Klasse neu, implementiert ihre Methode und weist sie einer Referenzvariablen zu, die vom selben Typ wie die eigentliche Klasse ist.
Es ist auch möglich, die neu implementierte Methode mit dieser Referenzvariablen aufzurufen.
Denken Sie daran, dass die neu implementierte anonyme Klasse eine Unterklasse der tatsächlichen Klasse ist.
Es folgt Polymorphismus und sein Objekt kann überall dort übergeben werden, wo das Objekt der Klasse erwartet wird.
Gehen Sie zur Veranschaulichung das folgende Beispiel durch.
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); }}
Anstatt die Implementierung der Website-Klasse vorab zu definieren, kann sie bei Bedarf definiert werden, dh beim Aufrufen der getWebsite-Methode.
Somit kann die Hauptmethode geändert werden als
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"); } });}
Die obige Implementierung ist keiner Referenzvariablen zugewiesen, sie hat keinen Namen und daher den Namen Anonymous.
B. Implementierer der Schnittstelle
Eine anonyme Klasse kann auch als Implementierer einer Schnittstelle definiert werden.
In diesem Fall definiert es die Implementierung von Methoden, die in der Schnittstelle deklariert sind, und kann überall dort übergeben werden, wo das Objekt der Schnittstelle erwartet wird.
Siehe unten Beispiel, um es klar zu machen.
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); }}
Wie zuvor kann die Implementierung der Schnittstelle als anonyme Klasse bei Bedarf wie unten gezeigt erstellt werden.
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"); } });}
new
vor dem Schnittstellennamen. Anonyme Klasse ist der einzige Ort, wo es möglich ist.Polymorphismus in anonymen Klassen
Wie bereits erwähnt, folgen anonyme Klassen dem Polymorphismus.
Da es sich um Unterklassen handelt, sollten sie dem Polymorphismus folgen. In diesem Abschnitt wird detailliert beschrieben, wie.
Betrachten Sie die folgende Klasse.
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(); }}
Der obige Code definiert eine Klasse Metal mit einer einzigen Methode.
Diese Klasse wird wieder anonym in einer anderen Klasse MetalDriver implementiert, wo eine neue Methode zu ihrer Definition hinzugefügt wird, die in der tatsächlichen Klasse nicht vorhanden ist.
Wenn diese neue Methode aufgerufen wird, beschwert sich der Compiler mit einem Fehler
Die Methode hasLustre() ist für den Typ Metal undefiniert.
Dies liegt daran, dass die anonyme Klasse eine Unterklasse ist, während die Referenz zur tatsächlichen Klasse gehört (die das übergeordnete Element ist).
Der Compiler konnte die neue Methode in der übergeordneten Klasse nicht finden und meldet einen Fehler.
Somit stellt der Fehler zwei Tatsachen fest:
(i) Anonyme Klasse ist eine Unterklasse der tatsächlichen Klasse, und
(ii) Anonyme Klassendefinitionen folgen Polymorphismus.
Verwendung der anonymen Klasse
Angenommen, Sie müssen eine Methode aufrufen, die ein Argument eines Typs verwendet, der eine Schnittstelle ist.
Nun gehört diese Schnittstelle zu einer externen Bibliothek und Sie haben keine Klasse, die diese Schnittstelle implementiert.
Wie werden Sie diese Methode aufrufen. Wenn Sie null
übergeben, besteht das Risiko von Laufzeitausnahmen.
Anonyme Klasse zur Rettung.
Jetzt können Sie eine anonyme Klasse erstellen, die diese Schnittstelle implementiert, und sie an die Methode übergeben, die die Implementierung ihrer Methoden gemäß Ihren Anforderungen bereitstellt.
Beispiel folgt.
// 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(); }}
Der obige Code verfügt über eine Schnittstelle mit einer einzelnen Methode und einer Klasse, deren Methode Sie aus Ihrem Code aufrufen müssen.
Methode dieser Klasse nimmt ein Argument vom Typ interface, aber Sie haben keine Klasse, die diese Schnittstelle implementiert.
Wenn Sie null
an das Methodenargument übergeben, wird sofort ein java.lang.NullPointerException
.
Sehen Sie sich an, wie Sie diese Methode mit der anonymen Klasse aufrufen können.
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 } }); }}
Beachten Sie die Verwendung einer anonymen Schnittstellenimplementierung zum Aufrufen der Methode.
Dies ist der größte Vorteil anonymer Klassen.
4. Statische verschachtelte Klasse
Eine statische Klasse, die in einer anderen Klasse definiert ist, ist eine statische verschachtelte Klasse. Es ist wie eine normale Klasse definiert, der das Schlüsselwort static vorangestellt ist.
Denken Sie daran, dass es nichts als statische Klasse gibt, eine statische verschachtelte Klasse ist nur ein statisches Mitglied ihrer äußeren Klasse.
Da es sich um ein statisches Element handelt, gilt Folgendes für eine statische verschachtelte Klasse.
- Die äußere Klasse kann direkt darauf zugreifen, ohne ihre Instanz zu haben.
- Es kann nur auf statische Member seiner äußeren Klasse zugreifen, nicht jedoch auf seine Instanzvariablen oder Methoden.
Beispiel für eine statische verschachtelte Klasse
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(); }}
Wie Sie dem obigen Beispiel entnehmen können, ist für den Zugriff auf eine statische verschachtelte Klasse keine Instanz der äußeren Klasse erforderlich, auf die direkt zugegriffen werden kann.
Beachten Sie, dass Objekte statischer verschachtelter Klassen nicht auf nicht statische Member äußerer Klassen zugreifen können. Im obigen Beispiel kann die verschachtelte Klasseninstanz outerMethod
der äußeren Klasse nicht aufrufen.
Lassen Sie uns
- Wenn eine Klasse, die eine innere Klasse enthält, kompiliert wird, werden 2 Klassendateien generiert:
eine für die äußere Klasse und eine für die innere Klasse.
Beispiel, Outer.class und Outer$Inner .klasse für äußere klasse Äußere und innere klasse Innere jeweils.. - Die Klassendatei der inneren Klasse kann nicht direkt mit dem Java-Befehl ausgeführt werden.
- Eine normale innere Klasse kann keine
static
Datenelemente oder Methoden haben. - Eine innere Klasse kann einen Konstruktor haben.
- Eine lokale Methodenklasse kann nur innerhalb der Methode instanziiert werden, in der sie definiert ist.
- Eine lokale Methodenklasse, die in
static
Methode definiert ist, kann nur aufstatic
Mitglieder der einschließenden Klasse zugreifen. - Eine anonyme Klasse, die eine Schnittstelle implementiert, kann nur eine Schnittstelle implementieren, im Gegensatz zu normalen Klassen, die viele implementieren können.
- Eine anonyme Klasse kann eine Klasse nicht erweitern und gleichzeitig eine Schnittstelle implementieren, die normale Klassen können.
- Anonyme Klassendefinitionen enden mit }; (Beachten Sie das Semikolon).
- Anonyme Klassen, die beim Aufruf einer Methode als Argument definiert werden, enden mit }); (Beachten Sie das Semikolon).
- Sie können keine Methode für anonyme Klassenreferenzen aufrufen, die in der tatsächlichen Klasse nicht vorhanden sind.
- Eine innere Klasse, der
static
vorangestellt ist, wird als verschachtelte Klasse und nicht als innere Klasse bezeichnet.
Leave a Reply