Porque, quando e onde usar Inner Class?

Pessoal,

Em uma conversa com um colega de trabalho nos deparamos com essa dúvida. Alguém poderia tentar nos ajudar?

Até porque sempre que penso em uma Inner Class, penso que o mesmo pode ser solucionado com um método ou uma nova classe ou até mesmo com uma outra classe no mesmo documento.

Se alguém puder me ajudar, ficarei grato.

Abraço a todos.

  1. Quando a sua classe só tem sentido dentro do escopo de outra classe. Por exemplo, a classe No de uma lista encadeada, só tem sentido dentro da lista encadeada. E será diferente da classe No de uma lista duplamente encadeada. Então, usar uma Inner Class é uma boa para evitar esses conflitos de nomes e para manter o escopo o mais reduzido possível;

  2. Inner class anônimas são úteis para escrever implementações para interfaces simples. Você nunca fez ou viu isso aqui?

janela.addWindowListener(new WindowAdapter() { public void windowClosing(WindowEvent e) { if (JOptionPane.showMessageDialog(Janela.this, "Deseja mesmo fechar?" != JOptionPane.YES_OPTION) return; dispose(); } }

  1. As inner classes não estáticas tem a vantagem de poder ver os métodos e atributos das classes que as agregam (como no exemplo ali em cima, a inner class anônima filha de WindowAdapter enxergou tanto o this quanto o dispose() da classe Janela). Isso pode simplificar muito o código.

Note que no caso da lista encadeada, a classe nó poderia não ter gets e sets, e isso acaba sendo seguro para o sistema como um todo, pois seu escopo ficou tão reduzido que pode ser interessante abrir mão de um pouco do encapsulamento em prol de um código simples dentro da classe ListaEncadeada.

  1. Para evitar violar o encapsulamento de sua classe principal. Por exemplo, vamos supor que você precise rodar uma parte do seu código dentro de uma thread. Você poderia ficar tentado a fazer sua classe implementar runnable:

[code]public class MinhaClasse implements Runnable
{
public void iniciar() {
new Thread(this).start();
}

public void parar() {
    parado = true;
}
public void run() {
    //Faz alguma coisa em outra thread
}

//resto da classe aqui

}[/code]

Essa classe deveria iniciar a thread no método iniciar e parar no método parar. Entretanto, do jeito que está aí, seu usuário pode fazer:

Ou mesmo:

Ambos os casos, um uso incorreto da sua classe. Isso ocorreu pq, para implementar Runnable, o método run() teve de ser deixado público,o que violou o encapsulamento de um trecho importante da sua classe principal. Para resolver isso, você pode deixar o trecho do Runnable numa inner class privada, evitando violar esse encapsulamento:

[code]public class MinhaClasse
{
public void iniciar() {
new Thread(new MinhaClasseRun()).start();
}

public void parar() {
    parado = true;
}

private class MinhaClasseRun implements Runnable {
public void run() {
//Faz alguma coisa em outra thread
}
}

//resto da classe aqui

}[/code]

Note que agora não é mais possível fazer as construções inválidas acima, afinal, sua classe principal não implementa Runnable.

Talvez essa apostila te ajude a entender melhor

http://www.de9.ime.eb.br/~madeira/teaching/labprog2/classes_internas.pdf

Abraços

Completando os posts anteriores…
Eu costumo usar inner classes muitas vezes pra criar uma Key de um mapa (cache por ex) interno. Essa key soh tem sentido no escopo da classe principal, entao por isso a key é uma inner.

Ex:


public class Foo{
  private static final Map<MyKey, Object> CACHE;
   //...

 private class MyKey{
   private String nome;
   private Integer idade;
 }  
}

Uma outra utilização comum de inner class é na implementação de interfaces, como nas classes do framework Collections. Abra o codigo fonte de ArrayList (e de toda sua hierarquia) por ex e vc verá a implemantação da interface Iterator la como uma inner.