Olá!

Hoje falarei um pouco sobre um assunto abordado nas provas de certificação de programador Java: Classes Internas (Inner Class). O conteúdo a ser abordado aqui não é nem de longe completo, já que este assunto é bem extenso. No entanto, o propósito deste post é ser um guia rápido para sanar eventuais dúvidas sobre o assunto ou simplesmente introduzir novos programadores ao tema.

Existem três razões pelas quais é interessante o uso de classes internas:

  1. Organização: principalmente quando a classe não irá ser usada em muitos contextos.
  2. Acesso: uma vez que classes internas podem acessar variáveis do classes externa.
  3. Conveniência: ter que criar um arquivo para cada classe as vezes é desnecessário.

As classes internas são dividas em duas categorias: estáticas e não estáticas. Dessas categorias, separamos em quatro tipos de classes internas:

  1. Classes internas estáticas: declaradas como membros estáticos de outra classe.
  2. Classes internas de instância: declaradas como membros de instância de outra classe.
  3. Classes internas locais: declaradas dentro de métodos de outras classes.
  4. Classes internas anônimas: são como classes internas locais, porém, escritas de outra forma.

Vamos nos aprofundar melhor em cada variância das classes internas.

Classes internas estáticas

Essas classes são declaradas como membros estáticos de outra classe, assim como outro membro estático qualquer. Na prática o nome da classe externa funcionará como um namespace da classe interna estática. 
package pizza;

public class Quadrada {

   public static class Queijo {

   }

   public static void main(String[] args) {

      //Modo de acesso a classe interna estática
      Quadrada.Queijo p = new Quadrada.Queijo();

   }
}
Outro ponto interessante é que torna-se possível acessar membros privados estáticos da classe interna a partir do objeto criado, no caso, p.

Classes internas de instância

Assim como as classes internas estáticas, as classes internas de instâncias são conhecidas pelo seu nome qualificado (<classe externa>.<classe interna>), mas dentro da classe externa ela pode ser conhecida simplesmente pelo seu nome. Uma classe interna de instância compartilha uma relação especial com sua externa. Na prática isso significa que a classe externa pode acessar os membros da classe interna e vice-versa (mesmo os privados).
//Este código é totalmente válido
public class Outer {

    private int i;
  
    public class Inner {

        private int inner_i;
     
        public void doit() {
            i = 5;
        }
    }

    public void doit() {
        Inner p = new Inner();
        p.inner_i = 3;
    }
}

A forma de instanciar a classe interna de instância é um pouco diferente da classe interna estática:
//Forma 1
Principal.Inner p = new Principal().new Inner();

//Forma 2
Principal p = new Principal();
Principal.Inner i = p.new Inner();

//Forma 3 (pode ser utilizada dentro da classe externa)
Inner i = new Inner();

Classes internas locais

É uma classe interna declarada no corpo do método. Seu acesso é dado simplesmente pelo nome da classe e esta precisa ser instanciada para ser utilizada. Outro ponto interessantes dessa classe interna é que ela pode acessar os membros finais do método que a engloba.

Pelo fato da classe interna local não fazer parte de uma classe externa ou pacote, modificadores de acesso a classe não são permitidos. No entanto, modificadores de acesso a membros da classe são permitidos normalmente).
public class Outer {

    public void doit() {

        final int i = 4;

        class Inner {

            private int inner_i;
         
            public void doit() {
                inner_i = i;
            }
        }

        //Deve ser instanciada para ser utilizada
        //Atenção: a instancia é declarada após a declaração da classe
        Inner p = new Inner();
        p.inner_i = 3;
    }
}

Classes internas anônimas

Uma classe interna anônima é uma outra forma de se escrever uma classe interna local. Neste modo de se escrever a classe você declara a classe e ela já retorna automaticamente uma instância da mesma (podendo assim serem escritas no local de um argumento de um método!!!).
public class Principal {
   
    public static void main(String[] args) {

        doit(new Inner() {
            public void doit() {
                System.out.println("Metodo da classe interna");
            }
        });
    }
   
    public static void doit(Inner i) {
        i.doit(); //Saida: Metodo da classe interna
    }
}

abstract class Inner{
    abstract public void doit();
}
As classes anônimas permitem que um método seja re-implementado diversas vezes, de acordo com a necessidade (vide exemplo):
public class Principal {

    public static void main(String[] args) {

        Inner i = new Inner(){
            public void doit(){
                System.out.println("Implementei o método!");
            }
        }; //Note que ela termina com ;
     
        i.doit(); //Saida: Implementei o método!
      
        i = new Inner(){
            public void doit(){
                System.out.println("Re-implementei o método!");
            }
        };
      
        i.doit(); //Saida: Re-implementei o método!
    }
}

abstract class Inner{
    abstract public void doit();
}
Por fim, outro ponto importante a ser citado sobre as classes internas anônimas é que elas permitem que interfaces sejam implementadas em tempo de declaração, assim como as classes (é o único modo permitido aplicar um new na interface!!!).

Então é isso pessoal. Curta a fan page do site e receba atualizações antes de todo mundo!
Até a próxima :)


Sobre o Autor:
Guilherme Oliveira
Guilherme Oliveira trabalha com desenvolvimento de software a mais de 10 anos. É técnico em informática, bacharel em ciência da computação, especialista em engenharia de software, além de ser Oracle Certified Java Programmer 6 (OCJP 6). Suas áreas preferidas são desenvolvimento web e games.

  1. gravatar

    # by GST Courses Delhi - 15 de setembro de 2017 às 04:02

    Great article, Thanks for your great information, the content is quiet interesting. I will be waiting for your next post.