Anonyma inre klasser och exempel - 1

"Hej, Amigo!"

"Men vi har redan sagt hej, Ellie!"

"Hej, bråka inte med din moster. På 3000-talet, om du inte har sett någon på mer än en halvtimme, är det vanligt att säga hej igen. Så ge mig inte din attityd!"

"Det är i alla fall dags för ett annat intressant ämne: robotreproduktion!"

"O_O."

"Skojar bara, det nya ämnet är anonyma inre klasser ."

"I Java finns det ibland situationer där du behöver en klass för att ärva flera klasser. Eftersom Java inte stöder multipelarv, har de löst det här problemet med inre klasser: i vår klass deklarerar vi en inre klass och gör den ärver vilken klass vi än behöver den för att ärva. Här är ett exempel:"

Exempel på en inre klass som ärver klassen Tråd
class Tiger extends Cat
{
 public void tigerRun()
 {
  .....
 }

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

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

"Låt oss gräva in ett annat exempel:"

Vi behöver en underklass av klassen Thread för att åsidosätta dess körmetod."

"Det är därför vi i Tiger-klassen deklarerade den inre klassen TigerThread , som ärver Thread och åsidosätter körmetoden.

"För enkelhetens skull definierade vi två metoder i Tiger-klassen: tigerRun och startTiger (som är analoga med Threads kör- och startmetoder."

"I tigerStart-metoden skapar vi ett TigerThread- objekt och anropar dess start()-metod."

"JVM kommer att skapa en ny tråd som börjar köras när TigerThreads körmetod anropas."

"Denna metod kallar sedan vår körmetod : tigerRun ."

"Jag har jobbat med trådar förut, så det här verkar okomplicerat."

"Måste vi namnge metoderna tigerRun och tigerStart?"

"Nej, vi kunde ha kallat dem springa och starta, men jag ville också visa att vi inte ärver Tråden. En förklaring hade kanske varit mer förvirrande."

"OK. Då tror jag att jag förstår det. Men om tigerStart anropas en andra gång, skapar vi och startar ett andra trådobjekt. Betyder det inte att vi kommer att ha «en tiger som kör på två olika trådar»? "

"Tja, är du inte skarp! Du har rätt, och det är inte bra. Låt oss skriva om koden så här:"

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

"Det är inte helt perfekt. Du kan fortfarande inte kalla en sådan metod två gånger. Men den här gången kommer vi åtminstone inte att skapa en andra tråd och få det att verka som att allt är bra."

"Det stämmer. Andra gången en Tiger startas får du ett undantag."

"Jag ser redan misstag bättre än du, Ellie!"

"Ja, du gör det bra. Låt oss sedan gå vidare till anonyma inre klasser."

"Observera flera aspekter av koden ovan:"

1) Vi ärvde klassen Thread, men implementerade praktiskt taget ingen kod där. "Det var mer "vi var tvungna att ärva trådklassen" snarare än "vi ärvde den för att förlänga den".

2) Endast ett TigerThread-objekt kommer att skapas.

Med andra ord skrev vi en hel massa kod bara för att åsidosätta en metod och skapa ett objekt.

Kommer du ihåg hur jag pratade om uppfinningen av konstruktörer?

Före konstruktörer Efter konstruktörer
TigerThread thread = new TigerThread();

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

"Jag ser att koden blev mer kompakt, men jag förstår inte riktigt vad som händer."

"Vi kan kombinera fyra saker till en:"

1) deklaration av en härledd klass

2) metod åsidosättande

3) deklaration av en variabel

4) skapande av en instans av en härledd klass.

"Faktum är att det vi gör är att kombinera två operationer: deklarera en härledd klass och skapa en instans av den klassen."

Utan anonym klass Med anonym klass
Cat tiger = new Tiger();

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

"Låt oss utforska syntaxen igen:"

Deklaration av en trådvariabel
Thread thread = new Thread();
Deklaration av en variabel vars typ är «en anonym klass som ärver tråden»
Thread thread = new Thread()
{

};

"Observera att vi inte bara definierar en ny klass. Vi skapar en variabel – det finns ett semikolon i slutet!"

"Och om vi vill åsidosätta körmetoden måste vi skriva detta:"

Deklaration av en trådvariabel
Thread thread = new Thread()
{
 public void run()
  {
   System.out.println("new run-method");
  }
};

"Du kommer snabbt ikapp. Bra jobbat!"

"Tack. Tänk om vi behöver andra metoder som inte ingår i trådklassen?"

"Du kan skriva dem."

"Även om det är anonymt är det här en fullfjädrad inre klass:"

Java-kod Beskrivning
Thread thread = new Thread()
{
  public void run()
  {
   printHi();
  }

  public void printHi()
  {
   System.out.println("Hi!");
  }
};
Röd: kod för att skapa variabeln.

Grön: kod för att skapa objektet.

Blå: kod för den anonymt härledda klassen.

"En fullvärdig inre klass?"

"Så jag kan använda variablerna för den yttre klassen?"

"Absolut."

"Och jag kan ge något till konstruktören?"

"Ja, men bara argumenten för superklassens konstruktör:"

Klass Exempel på en anonym inre klass
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);
  }
};

"Vi kan inte lägga till våra egna parametrar till någon annans konstruktor. Men vi kan använda variablerna i den yttre klassen, vilket kompenserar bra för denna brist."

"Vad händer om jag fortfarande verkligen behöver lägga till andra parametrar till konstruktorn?"

"Deklarera sedan en vanlig (icke-anonym) inre klass och använd den."

"Okej, jag glömde nästan bort det."

"Vad händer om jag deklarerar en statisk variabel? Skulle det göra att den anonyma klassen blir en statisk kapslad klass snarare än en inre klass? Med andra ord, kommer den att sakna en referens till den yttre klassen?"

"Nej. Det skulle vara en anonym inre klass. Titta på de här exemplen."

Med anonym klass Utan anonym klass
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();
 }
}

"Jag förstår. Bara den statiska variabeln skulle vara statisk, inte klassen."

"Japp."

"Faktum är att kompilatorn skapar inre klasser för alla anonyma inre klasser. Dessa klasser heter vanligtvis «1», «2», «3» osv.