Classes internas anônimas e exemplos - 1

"Olá, amigo!"

"Mas nós já dissemos olá, Ellie!"

"Ei, não discuta com sua tia. No século 31, se você não vê alguém por mais de meia hora, é costume dizer olá de novo. Então não me venha com essa atitude!"

"De qualquer forma, é hora de outro tópico interessante: reprodução de robôs!"

"O_O."

"Brincadeirinha, o novo tópico são classes internas anônimas ."

"Em Java, às vezes há situações em que você precisará de uma classe para herdar várias classes. Como Java não suporta herança múltipla, eles resolveram esse problema usando classes internas: em nossa classe, declaramos uma classe interna e fazemos ele herda qualquer classe que precisamos herdar. Aqui está um exemplo:"

Exemplo de uma classe interna que herda a 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();
  }
 }
}

"Vamos nos aprofundar em outro exemplo:"

Precisamos de uma subclasse da classe Thread para sobrescrever seu método run."

"É por isso que na classe Tiger declaramos a classe interna TigerThread , que herda Thread e substitui o método run.

"Por conveniência, definimos dois métodos na classe Tiger: tigerRun e startTiger (que são análogos aos métodos run e start de Thread."

"No método tigerStart, criamos um objeto TigerThread e invocamos seu método start()."

"A JVM criará um novo encadeamento que começará a ser executado quando o método run de TigerThread for chamado."

"Este método então chama nosso método de execução : tigerRun ."

"Já trabalhei com threads antes, então isso parece simples."

"Precisamos nomear os métodos tigerRun e tigerStart?"

"Não, poderíamos chamá-los de executar e iniciar, mas também queria demonstrar que não estamos herdando Thread. Uma explicação poderia ser mais confusa."

"OK. Acho que entendi. Mas se tigerStart for chamado uma segunda vez, criaremos e iniciaremos um segundo objeto Thread. Isso não significa que teremos «um tigre rodando em dois threads diferentes»? "

"Bem, você não é afiado! Você está certo, e isso não é bom. Vamos reescrever o código assim:"

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

"Não é perfeito. Você ainda não pode chamar um método como esse duas vezes. Mas desta vez, pelo menos não vamos criar um segundo thread e fazer parecer que está tudo bem."

"Isso mesmo. Na segunda vez que um Tiger for iniciado, você receberá uma exceção."

"Eu já estou detectando erros melhor do que você, Ellie!"

"Sim, você está indo muito bem. Então vamos passar para aulas internas anônimas."

"Observe vários aspectos do código acima:"

1) Herdamos a classe Thread, mas praticamente não implementamos nenhum código nela. "Foi mais «tivemos que herdar a classe Thread» em vez de «nós a herdamos para estendê-la».

2) Apenas um objeto TigerThread será criado.

Em outras palavras, escrevemos um monte de código apenas para substituir um método e criar um objeto.

Você se lembra de como eu falei sobre a invenção dos construtores?

Antes dos construtores Depois dos construtores
TigerThread thread = new TigerThread();

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

"Vejo que o código ficou mais compacto, mas não entendo muito bem o que está acontecendo."

"Podemos combinar quatro coisas em uma:"

1) declaração de uma classe derivada

2) substituição de método

3) declaração de uma variável

4) criação de uma instância de uma classe derivada.

"Na verdade, o que estamos fazendo é combinar duas operações: declarar uma classe derivada e criar uma instância dessa classe."

Sem aula anônima Com classe anônima
Cat tiger = new Tiger();

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

"Vamos explorar a sintaxe novamente:"

Declaração de uma variável Thread
Thread thread = new Thread();
Declaração de uma variável cujo tipo é «uma classe anônima que herda Thread»
Thread thread = new Thread()
{

};

"Observe que não estamos simplesmente definindo uma nova classe. Estamos criando uma variável - há um ponto-e-vírgula no final!"

"E se quisermos substituir o método run, precisamos escrever isto:"

Declaração de uma variável Thread
Thread thread = new Thread()
{
 public void run()
  {
   System.out.println("new run-method");
  }
};

"Você pega rápido. Muito bem!"

"Obrigado. E se precisarmos de outros métodos que não façam parte da classe Thread?"

"Você pode escrevê-los."

"Embora anônima, esta é uma classe interna completa:"

código Java Descrição
Thread thread = new Thread()
{
  public void run()
  {
   printHi();
  }

  public void printHi()
  {
   System.out.println("Hi!");
  }
};
Vermelho: código para criar a variável.

Verde: código para criação do objeto.

Azul: código para a classe derivada anônima.

"Uma classe interna completa?"

"Então posso usar as variáveis ​​da classe externa?"

"Absolutamente."

"E posso passar algo para o construtor?"

"Sim, mas apenas os argumentos para o construtor da superclasse:"

Aula Instância de uma classe interna anônima
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);
  }
};

"Não podemos adicionar nossos próprios parâmetros ao construtor de outra pessoa. Mas podemos usar as variáveis ​​da classe externa, o que compensa muito bem essa deficiência."

"E se eu ainda precisar adicionar outros parâmetros ao construtor?"

"Em seguida, declare uma classe interna comum (não anônima) e use-a."

"Certo, eu quase esqueci disso."

"E se eu declarar uma variável estática? Isso tornaria a classe anônima uma classe aninhada estática em vez de uma classe interna? Em outras palavras, faltará uma referência à classe externa?"

"Não. Seria uma classe interna anônima. Veja esses exemplos."

Com classe anônima Sem aula anônima
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();
 }
}

"Entendo. Apenas a variável estática seria estática, não a classe."

"Sim."

"Na verdade, o compilador cria classes internas para todas as classes internas anônimas. Essas classes são geralmente denominadas «1», «2», «3», etc.