Anonieme innerlijke klassen en voorbeelden - 1

"Hallo Amigo!"

'Maar we hebben al gedag gezegd, Ellie!'

"Hé, maak geen ruzie met je tante. Als je in de 31e eeuw iemand meer dan een half uur niet hebt gezien, is het gebruikelijk om weer hallo te zeggen. Dus geef me je houding niet!"

"Hoe dan ook, het is tijd voor een ander interessant onderwerp: robotreproductie!"

"O_O."

"Grapje, het nieuwe onderwerp is anonieme innerlijke klassen ."

"In Java zijn er soms situaties waarin je een klasse nodig hebt om meerdere klassen te erven. Aangezien Java geen meervoudige overerving ondersteunt, hebben ze dit probleem opgelost met behulp van interne klassen: in onze klasse declareren we een interne klasse en maken het erft elke klasse die we nodig hebben om te erven. Hier is een voorbeeld:"

Voorbeeld van een binnenklasse die de klasse Thread erft
class Tiger extends Cat
{
 public void tigerRun()
 {
  .....
 }

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

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

"Laten we een ander voorbeeld bekijken:"

We hebben een subklasse van de klasse Thread nodig om de run-methode te overschrijven."

"Daarom hebben we in de Tiger-klasse de TigerThread- binnenklasse gedeclareerd, die Thread erft en de run-methode overschrijft.

"Voor het gemak hebben we twee methoden gedefinieerd in de Tiger-klasse: tigerRun en startTiger (die analoog zijn aan de run- en start-methoden van Thread."

"In de tigerStart-methode maken we een TigerThread- object en roepen we de start()-methode aan."

"De JVM maakt een nieuwe thread die begint te draaien wanneer de run-methode van TigerThread wordt aangeroepen."

"Deze methode roept dan onze run- methode aan: tigerRun ."

"Ik heb eerder met threads gewerkt, dus dit lijkt eenvoudig."

"Moeten we de methoden tigerRun en tigerStart een naam geven?"

"Nee, we hadden ze rennen en starten kunnen noemen, maar ik wilde ook aantonen dat we Thread niet erven. Een verklaring was misschien verwarrender geweest."

"OK. Dan denk ik dat ik het snap. Maar als tigerStart een tweede keer wordt aangeroepen, zullen we een tweede Thread-object maken en starten. Betekent dat niet dat we "één tijger op twee verschillende threads" hebben? "

"Nou, ben je niet scherp! Je hebt gelijk, en dat is niet goed. Laten we de code als volgt herschrijven:"

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

"Het is niet helemaal perfect. Je kunt zo'n methode nog steeds geen twee keer aanroepen. Maar deze keer zullen we in ieder geval geen tweede thread maken en het laten lijken alsof alles in orde is."

"Dat klopt. De tweede keer dat een Tiger wordt gestart, krijg je een uitzondering."

"Ik zie fouten al beter dan jij, Ellie!"

"Ja, je doet het geweldig. Laten we dan verder gaan met anonieme innerlijke lessen."

"Let op verschillende aspecten van de bovenstaande code:"

1) We hebben de Thread-klasse geërfd, maar hebben daar praktisch geen code geïmplementeerd. "Het was meer 'we moesten de Thread-klasse erven' in plaats van 'we erfden het om het uit te breiden'.

2) Er wordt slechts één TigerThread-object gemaakt.

Met andere woorden, we hebben een hele reeks code geschreven om één methode te overschrijven en één object te maken.

Weet je nog hoe ik het had over de uitvinding van constructeurs?

Voor constructeurs Na constructeurs
TigerThread thread = new TigerThread();

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

"Ik zie dat de code compacter is geworden, maar ik begrijp niet helemaal wat er aan de hand is."

"We kunnen vier dingen combineren tot één:"

1) declaratie van een afgeleide klasse

2) methode overschrijven

3) declaratie van een variabele

4) creatie van een instantie van een afgeleide klasse.

"In feite combineren we twee bewerkingen: een afgeleide klasse declareren en een instantie van die klasse maken."

Zonder anonieme klasse Met anonieme klasse
Cat tiger = new Tiger();

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

"Laten we de syntaxis nog eens onderzoeken:"

Declaratie van een Thread-variabele
Thread thread = new Thread();
Declaratie van een variabele waarvan het type «een anonieme klasse die Thread erft» is
Thread thread = new Thread()
{

};

"Merk op dat we niet simpelweg een nieuwe klasse definiëren. We maken een variabele - er staat een puntkomma aan het einde!"

"En als we de run-methode willen overschrijven, dan moeten we dit schrijven:"

Declaratie van een Thread-variabele
Thread thread = new Thread()
{
 public void run()
  {
   System.out.println("new run-method");
  }
};

"Je snapt het snel. Goed gedaan!"

"Bedankt. Wat als we andere methoden nodig hebben die geen deel uitmaken van de klasse Thread?"

"Je kunt ze schrijven."

"Hoewel anoniem, is dit een volwaardige innerlijke klasse:"

Java-code Beschrijving
Thread thread = new Thread()
{
  public void run()
  {
   printHi();
  }

  public void printHi()
  {
   System.out.println("Hi!");
  }
};
Rood: code voor het maken van de variabele.

Groen: code voor het maken van het object.

Blauw: code voor de anonieme afgeleide klasse.

"Een volwaardige innerlijke klasse?"

"Dus ik kan de variabelen van de buitenste klasse gebruiken?"

"Absoluut."

"En ik kan iets doorgeven aan de constructeur?"

"Ja, maar alleen de argumenten voor de constructor van de superklasse:"

Klas Instantie van een anonieme innerlijke 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);
  }
};

"We kunnen onze eigen parameters niet toevoegen aan de constructor van iemand anders. Maar we kunnen de variabelen van de buitenste klasse gebruiken, wat deze tekortkoming mooi compenseert."

"Wat als ik toch echt andere parameters aan de constructor moet toevoegen?"

"Verklaar dan een gewone (niet-anonieme) innerlijke klasse en gebruik die."

"Oké, dat was ik bijna vergeten."

"Wat als ik een statische variabele declareer? Zou de anonieme klasse daardoor een statische geneste klasse worden in plaats van een binnenklasse? Met andere woorden, zal het een verwijzing naar de buitenklasse missen?"

"Nee. Het zou een anonieme innerlijke klas zijn. Kijk naar deze voorbeelden."

Met anonieme klasse Zonder anonieme klasse
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();
 }
}

"Ik begrijp het. Alleen de statische variabele zou statisch zijn, niet de klasse."

"Ja."

"In feite maakt de compiler innerlijke klassen voor alle anonieme innerlijke klassen. Deze klassen worden gewoonlijk «1», «2», «3», enz. genoemd.