Classi interne anonime ed esempi - 1

"Ciao, Amico!"

"Ma ci siamo già salutati, Ellie!"

"Ehi, non discutere con tua zia. Nel 31° secolo, se non vedi qualcuno da più di mezz'ora, è consuetudine salutare di nuovo. Quindi non darmi il tuo atteggiamento!"

"Comunque, è il momento di un altro argomento interessante: la riproduzione dei robot!"

"O_O."

"Sto scherzando, il nuovo argomento sono le classi interne anonime ."

"In Java, a volte ci sono situazioni in cui avrai bisogno di una classe per ereditare diverse classi. Poiché Java non supporta l'ereditarietà multipla, hanno risolto questo problema usando le classi interne: nella nostra classe, dichiariamo una classe interna e creiamo eredita qualunque classe ci serva per ereditare. Ecco un esempio:"

Esempio di una classe interna che eredita la classe Thread
class Tiger extends Cat
{
 public void tigerRun()
 {
  .....
 }

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

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

"Facciamo un altro esempio:"

Abbiamo bisogno di una sottoclasse della classe Thread per sovrascrivere il suo metodo run."

"Ecco perché nella classe Tiger abbiamo dichiarato la classe interna TigerThread , che eredita Thread e sovrascrive il metodo run.

"Per comodità, abbiamo definito due metodi nella classe Tiger: tigerRun e startTiger (che sono analoghi ai metodi run e start di Thread."

"Nel metodo tigerStart, creiamo un oggetto TigerThread e invochiamo il suo metodo start()."

"La JVM creerà un nuovo thread che inizierà a funzionare quando viene chiamato il metodo run di TigerThread ."

"Questo metodo chiama quindi il nostro metodo run : tigerRun ."

"Ho già lavorato con i thread, quindi sembra semplice."

"Dobbiamo nominare i metodi tigerRun e tigerStart?"

"No, avremmo potuto chiamarli corri e inizia, ma volevo anche dimostrare che non stiamo ereditando Thread. Una spiegazione avrebbe potuto essere più confusa."

"OK. Allora penso di aver capito. Ma se tigerStart viene chiamato una seconda volta, creeremo e avvieremo un secondo oggetto Thread. Non significa che avremo «una tigre in esecuzione su due thread diversi»? "

"Beh, non sei intelligente! Hai ragione, e non va bene. Riscriviamo il codice in questo modo:"

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

"Non è del tutto perfetto. Non puoi ancora chiamare un metodo del genere due volte. Ma questa volta, almeno non creeremo un secondo thread e faremo sembrare che tutto vada bene."

"Esatto. La seconda volta che viene avviato un Tiger, avrai un'eccezione."

"Sto già individuando gli errori meglio di te, Ellie!"

"Sì, stai andando alla grande. Allora passiamo alle classi interne anonime."

"Nota diversi aspetti del codice sopra:"

1) Abbiamo ereditato la classe Thread, ma praticamente non abbiamo implementato alcun codice. "Era più «abbiamo dovuto ereditare la classe Thread» piuttosto che «l'abbiamo ereditata per estenderla».

2) Verrà creato un solo oggetto TigerThread.

In altre parole, abbiamo scritto un sacco di codice solo per sovrascrivere un metodo e creare un oggetto.

Ricordi come ho parlato dell'invenzione dei costruttori?

Prima dei costruttori Dopo i costruttori
TigerThread thread = new TigerThread();

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

"Vedo che il codice è diventato più compatto, ma non capisco bene cosa stia succedendo."

"Possiamo combinare quattro cose in una:"

1) dichiarazione di una classe derivata

2) sostituzione del metodo

3) dichiarazione di una variabile

4) creazione di un'istanza di una classe derivata.

"In effetti, quello che stiamo facendo è combinare due operazioni: dichiarare una classe derivata e creare un'istanza di quella classe."

Senza classe anonima Con classe anonima
Cat tiger = new Tiger();

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

"Esploriamo di nuovo la sintassi:"

Dichiarazione di una variabile Thread
Thread thread = new Thread();
Dichiarazione di una variabile il cui tipo è «una classe anonima che eredita Thread»
Thread thread = new Thread()
{

};

"Nota che non stiamo semplicemente definendo una nuova classe. Stiamo creando una variabile—c'è un punto e virgola alla fine!"

"E se vogliamo sovrascrivere il metodo run, allora dobbiamo scrivere questo:"

Dichiarazione di una variabile Thread
Thread thread = new Thread()
{
 public void run()
  {
   System.out.println("new run-method");
  }
};

"Hai capito in fretta. Ben fatto!"

"Grazie. E se avessimo bisogno di altri metodi che non fanno parte della classe Thread?"

"Puoi scriverli."

"Sebbene anonima, questa è una classe interna a tutti gli effetti:"

codice java Descrizione
Thread thread = new Thread()
{
  public void run()
  {
   printHi();
  }

  public void printHi()
  {
   System.out.println("Hi!");
  }
};	 
Rosso: codice per la creazione della variabile.

Verde: codice per la creazione dell'oggetto.

Blu: codice per la classe derivata anonima.

"Una classe interna a tutti gli effetti?"

"Quindi posso usare le variabili della classe esterna?"

"Assolutamente."

"E posso passare qualcosa al costruttore?"

"Sì, ma solo gli argomenti per il costruttore della superclasse:"

Classe Istanza di una classe interna anonima
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);
  }
};

"Non possiamo aggiungere i nostri parametri al costruttore di qualcun altro. Ma possiamo usare le variabili della classe esterna, che compensa bene questa mancanza."

"E se avessi ancora davvero bisogno di aggiungere altri parametri al costruttore?"

"Quindi dichiara una classe interna ordinaria (non anonima) e usala."

"Giusto, me ne ero quasi dimenticato."

"E se dichiaro una variabile statica? Ciò renderebbe la classe anonima una classe nidificata statica piuttosto che una classe interna? In altre parole, mancherebbe un riferimento alla classe esterna?"

"No. Sarebbe una classe interna anonima. Guarda questi esempi."

Con classe anonima Senza classe anonima
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();
 }
}

"Capisco. Solo la variabile statica sarebbe statica, non la classe."

"Sì."

"In effetti, il compilatore crea classi interne per tutte le classi interne anonime. Queste classi sono solitamente denominate «1», «2», «3», ecc."