Anonyme innere Klassen und Beispiele – 1

„Hallo, Amigo!“

„Aber wir haben schon Hallo gesagt, Ellie!“

„Hey, streite nicht mit deiner Tante. Im 31. Jahrhundert ist es üblich, noch einmal Hallo zu sagen, wenn du jemanden länger als eine halbe Stunde nicht gesehen hast. Also verrate mir nicht deine Einstellung!“

„Wie auch immer, es ist Zeit für ein weiteres interessantes Thema: die Roboterreproduktion!“

„O_O.“

„Nur ein Scherz, das neue Thema sind anonyme innere Klassen .“

„In Java gibt es manchmal Situationen, in denen Sie eine Klasse benötigen, um mehrere Klassen zu erben. Da Java keine Mehrfachvererbung unterstützt, haben sie dieses Problem mithilfe innerer Klassen gelöst: In unserer Klasse deklarieren wir eine innere Klasse und erstellen sie Es erbt jede Klasse, die es erben muss. Hier ist ein Beispiel:

Beispiel einer inneren Klasse, die die Thread-Klasse erbt
class Tiger extends Cat
{
 public void tigerRun()
 {
  .....
 }

 public void startTiger()
 {
  TigerThread thread = new TigerThread();
  thread.start();
 }

 class TigerThread extends Thread
 {
  public void run()
  {
   tigerRun();
  }
 }
}

„Sehen wir uns ein anderes Beispiel an:“

Wir benötigen eine Unterklasse der Thread-Klasse, um deren Ausführungsmethode zu überschreiben.

„Deshalb haben wir in der Tiger-Klasse die innere Klasse TigerThread deklariert , die Thread erbt und die run-Methode überschreibt.

„Der Einfachheit halber haben wir zwei Methoden in der Tiger-Klasse definiert: tigerRun und startTiger (die analog zu den run- und start-Methoden von Thread sind.“

„In der tigerStart-Methode erstellen wir ein TigerThread- Objekt und rufen dessen start()-Methode auf.“

„Die JVM erstellt einen neuen Thread, der mit der Ausführung beginnt, wenn die run-Methode von TigerThread aufgerufen wird.“

„Diese Methode ruft dann unsere Ausführungsmethode auf : tigerRun .“

„Ich habe schon früher mit Threads gearbeitet, daher scheint das einfach zu sein.“

„Müssen wir die Methoden TigerRun und TigerStart nennen?“

„Nein, wir hätten sie „Run“ und „Start“ nennen können, aber ich wollte auch zeigen, dass wir Thread nicht erben. Eine Erklärung wäre vielleicht verwirrender gewesen.“

„OK. Dann denke ich, dass ich es verstanden habe. Aber wenn tigerStart ein zweites Mal aufgerufen wird, erstellen und starten wir ein zweites Thread-Objekt. Bedeutet das nicht, dass wir „einen Tiger haben, der auf zwei verschiedenen Threads läuft“? "

„Na, bist du nicht scharfsinnig! Du hast recht, und das ist nicht gut. Lass uns den Code so umschreiben:“

Code
class Tiger extends Cat
{
 public void tigerRun()
 {
  .....
 }

 public void startTiger()
 {
  thread.start();
 }

 private TigerThread thread = new TigerThread();

 private class TigerThread extends Thread
 {
  public void run()
  {
   tigerRun();
  }
 }
}

„Es ist nicht ganz perfekt. Man kann eine solche Methode immer noch nicht zweimal aufrufen. Aber dieses Mal werden wir zumindest keinen zweiten Thread erstellen und es so aussehen lassen, als wäre alles in Ordnung.“

„Das stimmt. Beim zweiten Start eines Tigers erhalten Sie eine Ausnahme.“

„Ich erkenne Fehler schon besser als du, Ellie!“

„Ja, du machst das großartig. Dann lass uns zu anonymen inneren Klassen übergehen.“

„Beachten Sie mehrere Aspekte des obigen Codes:“

1) Wir haben die Thread-Klasse geerbt, dort aber praktisch keinen Code implementiert. „Es ging eher um „wir mussten die Thread-Klasse erben“ als um „wir haben sie geerbt, um sie zu erweitern“.

2) Es wird nur ein TigerThread-Objekt erstellt.

Mit anderen Worten: Wir haben eine ganze Menge Code geschrieben, nur um eine Methode zu überschreiben und ein Objekt zu erstellen.

Erinnern Sie sich, wie ich über die Erfindung der Konstrukteure gesprochen habe?

Vor Konstrukteuren Nach Konstrukteuren
TigerThread thread = new TigerThread();

private class TigerThread extends Thread
{
 public void run()
 {
  tigerRun();
 }
}
Thread thread = new Thread()
{
 public void run()
 {
  tigerRun();
 }
};

„Ich sehe, dass der Code kompakter geworden ist, aber ich verstehe nicht ganz, was passiert.“

„Wir können vier Dinge zu einem kombinieren:“

1) Deklaration einer abgeleiteten Klasse

2) Methodenüberschreibung

3) Deklaration einer Variablen

4) Erstellung einer Instanz einer abgeleiteten Klasse.

„Tatsächlich kombinieren wir zwei Operationen: die Deklaration einer abgeleiteten Klasse und die Erstellung einer Instanz dieser Klasse.“

Ohne anonymen Unterricht Mit anonymer Klasse
Cat tiger = new Tiger();

class Tiger extends Cat
{
}
Cat tiger = new Cat()
{
};

„Lassen Sie uns die Syntax noch einmal untersuchen:“

Deklaration einer Thread-Variablen
Thread thread = new Thread();
Deklaration einer Variablen vom Typ „eine anonyme Klasse, die Thread erbt“
Thread thread = new Thread()
{

};

„Beachten Sie, dass wir nicht einfach eine neue Klasse definieren. Wir erstellen eine Variable – am Ende steht ein Semikolon!“

„Und wenn wir die run-Methode überschreiben wollen, müssen wir Folgendes schreiben:“

Deklaration einer Thread-Variablen
Thread thread = new Thread()
{
 public void run()
  {
   System.out.println("new run-method");
  }
};

„Du verstehst es schnell. Gut gemacht!“

„Danke. Was ist, wenn wir andere Methoden benötigen, die nicht Teil der Thread-Klasse sind?“

„Du kannst sie schreiben.“

„Obwohl anonym, ist dies eine vollwertige innere Klasse:“

Java-Code Beschreibung
Thread thread = new Thread()
{
  public void run()
  {
   printHi();
  }

  public void printHi()
  {
   System.out.println("Hi!");
  }
};	 
Rot: Code zum Erstellen der Variable.

Grün: Code zum Erstellen des Objekts.

Blau: Code für die anonyme abgeleitete Klasse.

„Eine vollwertige innere Klasse?“

„Also kann ich die Variablen der äußeren Klasse verwenden?“

"Absolut."

„Und ich kann dem Konstrukteur etwas übergeben?“

„Ja, aber nur die Argumente für den Konstruktor der Oberklasse:“

Klasse Instanz einer anonymen inneren Klasse
class Cat
{
 int x, y;
 Cat(int x, int y)
 {
  this.x = x;
  thix.y = y;
 }
}
Cat cat = new Cat(3,4)
{
  public void print()
  {
   System.out.println(x+" "+y);
  }
};

„Wir können unsere eigenen Parameter nicht zum Konstruktor eines anderen hinzufügen. Aber wir können die Variablen der äußeren Klasse verwenden, was dieses Manko gut ausgleicht.“

„Was ist, wenn ich dem Konstruktor wirklich noch weitere Parameter hinzufügen muss?“

„Dann deklarieren Sie eine gewöhnliche (nicht anonyme) innere Klasse und verwenden Sie diese.“

„Richtig, das hätte ich fast vergessen.“

„Was wäre, wenn ich eine statische Variable deklariere? Würde die anonyme Klasse dadurch zu einer statisch verschachtelten Klasse und nicht zu einer inneren Klasse? Mit anderen Worten: Fehlt ihr ein Verweis auf die äußere Klasse?“

„Nein. Es wäre eine anonyme innere Klasse. Schauen Sie sich diese Beispiele an.“

Mit anonymer Klasse Ohne anonymen Unterricht
Thread thread = new Thread()
{
  public void run()
  {
   tigerRun();
  }
};
TigerThread thread = new TigerThread();

private class TigerThread extends Thread
{
 public void run()
 {
  tigerRun();
 }
}
static Thread thread = new Thread()
{
  public void run()
  {
   tigerRun();
  }
};
static TigerThread thread = new TigerThread();

private class TigerThread extends Thread
{
 public void run()
 {
  tigerRun();
 }
}

„Ich verstehe. Nur die statische Variable wäre statisch, nicht die Klasse.“

"Ja."

„Tatsächlich erstellt der Compiler innere Klassen für alle anonymen inneren Klassen. Diese Klassen werden normalerweise „1“, „2“, „3“ usw. genannt.“