CodeGym /Blogue Java /Random-PT /aulas anônimas
John Squirrels
Nível 41
San Francisco

aulas anônimas

Publicado no grupo Random-PT
Oi! Na lição de hoje, continuaremos a examinar o tópico de classes aninhadas. Agora é a vez do último grupo: classes internas anônimas. Voltemos ao nosso diagrama: Turmas anônimas - 2Assim como as classes locais de que falamos na última lição, as classes anônimas são uma espécie de classe interna... Elas também têm várias semelhanças e diferenças. Mas primeiro, vamos nos aprofundar: por que exatamente eles são chamados de "anônimos"? Para responder a isso, considere um exemplo simples. Imagine que temos um programa básico que está constantemente rodando e fazendo alguma coisa. Queremos criar um sistema de monitoramento para este programa, composto por vários módulos. Um módulo rastreará indicadores gerais de desempenho e manterá um registro. O segundo registrará e registrará os erros em um log de erros. O terceiro rastreará atividades suspeitas: por exemplo, tentativas de acesso não autorizado e outras coisas relacionadas à segurança. Como todos os três módulos devem, em essência, simplesmente iniciar no início do programa e executar em segundo plano,

public interface MonitoringSystem {
  
   public void startMonitoring();
}
3 classes concretas irão implementá-lo:

public class GeneralIndicatorMonitoringModule implements MonitoringSystem {
   
@Override
   public void startMonitoring() {
       System.out.println("Starting to monitor general indicators!");
   }
}


public class ErrorMonitoringModule implements MonitoringSystem {

   @Override
   public void startMonitoring() {
       System.out.println("Starting to monitor errors!");
   }
}


public class SecurityModule implements MonitoringSystem {

   @Override
   public void startMonitoring() {
       System.out.println("Starting to monitor security!");
   }
}
Parece que tudo está em ordem. Temos um sistema bastante coerente composto por vários módulos. Cada um deles tem seu próprio comportamento. Se precisarmos de novos módulos, podemos adicioná-los, pois temos uma interface bastante fácil de implementar. Mas vamos pensar em como nosso sistema de monitoramento funcionará. Turmas anônimas - 3Basicamente, só precisamos criar 3 objetos — GeneralIndicatorMonitoringModule, ErrorMonitoringModule, SecurityModule— e chamar o startMonitoring()método de cada um deles. Ou seja, tudo o que precisamos fazer é criar 3 objetos e chamar 1 método neles.

public class Main {

   public static void main(String[] args) {

       GeneralIndicatorMonitoringModule generalModule = new GeneralIndicatorMonitoringModule();
       ErrorMonitoringModule errorModule = new ErrorMonitoringModule();
       SecurityModule securityModule = new SecurityModule();

       generalModule.startMonitoring();
       errorModule.startMonitoring();
       securityModule.startMonitoring();
   }
}
Saída do console:

Starting to monitor general indicators! 
Starting to monitor errors! 
Starting to monitor security!
E com tão pouco trabalho, escrevemos todo o sistema: 3 classes e uma interface! E tudo isso para atingir 6 linhas de código. Por outro lado, quais são as nossas opções? Bem, não é muito legal termos escrito essas aulas "únicas". Mas como podemos consertar isso? Aqui classes internas anônimas vêm em nosso socorro! Veja como eles se parecem no nosso caso:

public class Main {

   public static void main(String[] args) {

       MonitoringSystem generalModule = new MonitoringSystem() {
           @Override
           public void startMonitoring() {
               System.out.println("Starting to monitor general indicators!");
           }
       };

       

MonitoringSystem errorModule = new MonitoringSystem() {
           @Override
           public void startMonitoring() {
               System.out.println("Starting to monitor errors!");
           }
       };

       MonitoringSystem securityModule = new MonitoringSystem() {
           @Override
           public void startMonitoring() {
               System.out.println("Starting to monitor security!");
           }
       };

       generalModule.startMonitoring();
       errorModule.startMonitoring();
       securityModule.startMonitoring();
   }
}
Vamos descobrir o que está acontecendo! Parece que estamos criando um objeto de interface:

MonitoringSystem generalModule = new MonitoringSystem() {
   
@Override
   public void startMonitoring() {
       System.out.println("Starting to monitor general indicators!");
   }
};
Mas sabemos há muito tempo que não podemos criar objetos de interface! E assim é - é impossível. Na verdade, não é isso que estamos fazendo. Quando escrevemos:

MonitoringSystem generalModule = new MonitoringSystem() {
   
};
o seguinte acontece dentro da máquina Java:
  1. É criada uma classe Java sem nome que implementa a MonitoringSysteminterface.
  2. Quando o compilador vê tal classe, ele exige que você implemente todos os métodos da MonitoringSysteminterface (fizemos isso 3 vezes).
  3. Um objeto desta classe é criado. Preste atenção no código:

MonitoringSystem generalModule = new MonitoringSystem() {
   
};
Tem ponto e vírgula no final! Está lá por uma razão. Simultaneamente declaramos a classe (usando chaves) e criamos uma instância dela (usando ();). Cada um dos nossos três objetos substitui o startMonitoring()método à sua maneira. Por fim, simplesmente chamamos esse método em cada um deles:

generalModule.startMonitoring();
errorModule.startMonitoring();
securityModule.startMonitoring();
Saída do console:

Starting to monitor general indicators! 
Starting to monitor errors! 
Starting to monitor security!
É isso! Atingimos nosso objetivo: criamos três MonitoringSystemobjetos, sobrescrevemos um método de três maneiras diferentes e o chamamos três vezes. Todos os três módulos foram chamados com sucesso e estão em execução. Ao mesmo tempo, a estrutura do nosso programa ficou muito mais simples! Afinal, as classes GeneralIndicatorMonitoringModule, ErrorMonitoringModule, e SecurityModuleagora podem ser totalmente removidas do programa! Simplesmente não precisamos deles - fizemos um ótimo trabalho sem eles. Se cada uma de nossas classes anônimas precisar de algum comportamento diferente, por exemplo, seus próprios métodos específicos que as outras não possuem, podemos adicioná-los facilmente:

MonitoringSystem generalModule = new MonitoringSystem() {
  
   @Override
   public void startMonitoring() {
       System.out.println("Starting to monitor general indicators!");
   }
  
   public void someSpecificMethod() {

       System.out.println("Specific method only for the first module");
   }
};
A documentação do Oracle fornece uma boa recomendação : "Use [classes anônimas] se precisar usar uma classe local apenas uma vez." Uma classe anônima é uma classe interna completa. Assim, ele tem acesso às variáveis ​​da classe externa, incluindo variáveis ​​estáticas e privadas:

public class Main {

   private static int currentErrorCount = 23;

   public static void main(String[] args) {

       MonitoringSystem errorModule = new MonitoringSystem() {
          
           @Override
           public void startMonitoring() {
               System.out.println("Starting to monitor errors!");
           }

           public int getCurrentErrorCount() {

               return currentErrorCount;
           }
       };
   }
}
Elas têm algo em comum com as classes locais: são visíveis apenas dentro do método em que são declaradas. No exemplo acima, qualquer tentativa de acessar o errorModuleobjeto fora do main()método falhará. E há mais uma limitação importante que as classes anônimas herdam de seus "ancestrais" (classes internas): uma classe anônima não pode conter variáveis ​​e métodos estáticos . No exemplo acima, se tentarmos tornar o getCurrentErrorCount()método estático, o compilador irá gerar um erro:

// Error! Inner classes cannot have static declarations
public static int getCurrentErrorCount() {

   return currentErrorCount;
}
Obtemos o mesmo resultado se tentarmos declarar uma variável estática:

MonitoringSystem errorModule = new MonitoringSystem() {

   // Error! Inner classes cannot have static declarations!
   static int staticInt = 10;

   @Override
   public void startMonitoring() {
       System.out.println("Starting to monitor errors!");
   }

};
E nossa aula de hoje chegou ao fim! Mas, embora tenhamos investigado o último grupo de classes aninhadas, ainda não terminamos este tópico. O que mais aprenderemos sobre classes aninhadas? Certamente você descobrirá em breve! :)
Comentários
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION