Névtelen belső osztályok és példák - 1

– Szia Amigo!

– De már köszöntünk, Ellie!

"Hé, ne vitatkozz a nénivel. A 31. században, ha nem láttál valakit több mint fél órán keresztül, akkor szokás újra köszönni. Szóval ne mondd el a hozzáállásod!"

– Mindenesetre itt az ideje egy újabb érdekes témának: a robotreprodukciónak!

"O_O."

"Csak viccelek, az új téma az anonim belső osztályok ."

"A Java-ban néha előfordulnak olyan helyzetek, amikor szükség van egy osztályra több osztály örökléséhez. Mivel a Java nem támogatja a többszörös öröklődést, ezt a problémát belső osztályokkal oldották meg: a mi osztályunkban deklarálunk egy belső osztályt, és azt az osztályt örökli, amelyet örökölnünk kell. Íme egy példa:"

Példa egy belső osztályra, amely örökli a Thread osztályt
class Tiger extends Cat
{
 public void tigerRun()
 {
  .....
 }

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

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

– Vegyünk egy másik példát:

Szükségünk van a Thread osztály egy alosztályára, hogy felülbírálhassuk a futtatási metódusát."

"Ezért a Tiger osztályban deklaráltuk a TigerThread belső osztályt, amely örökli a Threadet, és felülírja a futtatási metódust.

"A kényelem kedvéért két metódust definiáltunk a Tiger osztályban: a tigerRun-t és a startTiger-t (amelyek a Thread futtatási és indítási metódusaihoz hasonlóak."

"A tigerStart metódusban létrehozunk egy TigerThread objektumot, és meghívjuk a start() metódusát."

"A JVM új szálat hoz létre, amely a TigerThread futtatási metódusának meghívásakor elindul ."

"Ez a metódus ezután meghívja a futtatási metódusunkat: tigerRun ."

– Dolgoztam már szálakkal, szóval ez egyértelműnek tűnik.

"Meg kell neveznünk a tigerRun és a tigerStart metódusokat?"

"Nem, hívhattuk volna őket futni és indulni, de azt is be akartam mutatni, hogy nem örököljük Threadot. A magyarázat talán zavaróbb lett volna."

"Rendben. Akkor azt hiszem, értem. De ha a tigerStart másodszor is meghívásra kerül, akkor létrehozunk és elindítunk egy második Thread objektumot. Ez nem azt jelenti, hogy "egy tigris két különböző szálon fut"? "

"Hát nem éles vagy! Igazad van, és ez nem jó. Írjuk át a kódot így:"

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

"Nem egészen tökéletes. Egy ilyen módszert továbbra sem hívhatsz meg kétszer. De ezúttal legalább nem hozunk létre egy második szálat, és úgy tűnik, hogy minden rendben van."

"Így van. Amikor egy Tigrist másodszor elindítanak, kivételt kapsz."

– Én már jobban észreveszem a hibákat, mint te, Ellie!

"Igen, remekül csinálod. Akkor térjünk át az anonim belső osztályokra."

"Jegyezze meg a fenti kód néhány szempontját:"

1) Megörököltük a Thread osztályt, de ott gyakorlatilag nem implementáltunk kódot. "Inkább "örökölnünk kellett a Thread osztályt", nem pedig "örököltük, hogy meghosszabbítsuk".

2) Csak egy TigerThread objektum jön létre.

Más szóval, egy csomó kódot írtunk csak azért, hogy felülbíráljunk egy metódust és létrehozzunk egy objektumot.

Emlékszel, hogyan beszéltem a konstruktorok feltalálásáról?

A kivitelezők előtt A kivitelezők után
TigerThread thread = new TigerThread();

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

"Látom, hogy a kód tömörebb lett, de nem egészen értem, mi történik."

"Négy dolgot kombinálhatunk egybe:"

1) származtatott osztály deklarációja

2) módszer felülbírálása

3) egy változó deklarálása

4) származtatott osztály példányának létrehozása.

"Valójában két műveletet kombinálunk: deklarálunk egy származtatott osztályt, és létrehozzuk az osztály példányát."

Névtelen osztály nélkül Névtelen osztállyal
Cat tiger = new Tiger();

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

"Fedezzük fel újra a szintaxist:"

Egy szál változó deklarációja
Thread thread = new Thread();
Egy olyan változó deklarációja, amelynek típusa "egy névtelen osztály, amely örökli a szálat"
Thread thread = new Thread()
{

};

"Ne feledje, hogy nem egyszerűen egy új osztályt definiálunk. Változót hozunk létre – pontosvessző van a végén!"

"És ha felül akarjuk írni a futtatási metódust, akkor ezt kell írnunk:"

Egy szál változó deklarációja
Thread thread = new Thread()
{
 public void run()
  {
   System.out.println("new run-method");
  }
};

"Gyorsan felfogod. Jó volt!"

"Köszönöm. Mi van, ha más metódusokra van szükségünk, amelyek nem tartoznak a Thread osztályba?"

– Megírhatod őket.

"Bár névtelen, ez egy teljes értékű belső osztály:"

Java kód Leírás
Thread thread = new Thread()
{
  public void run()
  {
   printHi();
  }

  public void printHi()
  {
   System.out.println("Hi!");
  }
};	 
Piros: kód a változó létrehozásához.

Zöld: kód az objektum létrehozásához.

Kék: az anonim származtatott osztály kódja.

– Teljes értékű belső osztály?

– Tehát használhatom a külső osztály változóit?

"Teljesen."

– És átadhatok valamit a kivitelezőnek?

"Igen, de csak a szuperosztály konstruktora melletti érvek:"

Osztály Egy névtelen belső osztály példánya
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);
  }
};

"Nem adhatjuk hozzá saját paramétereinket valaki más konstruktorához. De használhatjuk a külső osztály változóit, ami szépen kompenzálja ezt a hiányosságot."

"Mi van akkor, ha mégis tényleg más paramétereket kell hozzáadnom a konstruktorhoz?"

"Akkor deklarálj egy közönséges (nem névtelen) belső osztályt, és használd azt."

– Helyes, majdnem megfeledkeztem róla.

"Mi van, ha deklarálok egy statikus változót? Ettől az anonim osztály statikus beágyazott osztály lesz, nem pedig belső osztály? Más szóval, nem lesz utalás a külső osztályra?"

"Nem. Ez egy névtelen belső osztály lenne. Nézd meg ezeket a példákat."

Névtelen osztállyal Névtelen osztály nélkül
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();
 }
}

"Értem. Csak a statikus változó lenne statikus, az osztály nem."

"Igen."

"Valójában a fordító minden anonim belső osztályhoz belső osztályokat hoz létre. Ezeket az osztályokat általában «1», «2», «3» stb.-nek nevezik."