Início‎ > ‎

Não usar classes internas (“inner class”)

Classes internas são classes declaradas dentro de outras classes. Um exemplo seria:

public class FixedStack {
  Object[] array;
  int top = 0;

  class MyEnum implements java.util.Enumerator {
    // esta é a clase interna.
    int count = top;
    public boolean hasMoreElements() { return count > 0; }
    public Object nextElement() {
      if (count == 0)
      throw new NoSuchElementException(“FixedStack”);
       return array[--count]; }
  }

  public java.util.Enumerator enumerateAll() {
    return new MyEnum();
    }
}

O primeiro problema com o uso de classes internas é que campos privados da classe externa são diretamente acessíveis às classes internas. Como as classes internas podem ser declaradas públicas e, portanto, acessadas pelas demais classes do sistema. Desta forma, o programador pode, sem perceber, criar vazamentos de informações privadas através dos métodos da classe interna. O exemplo abaixo mostra como isso pode acontecer:

class Coordinates {
private int x;
private int y;

public class Point {
public void getPoint() {
System.out.println("(" + x + "," + y + ")");
}
}
}

class AnotherClass {
public static void main(String[] args) {
Coordinates c = new Coordinates();
Coordinates.Point p = c.new Point();
p.getPoint();
}
}

Neste exemplo, os campos x e y podem ser acessados por qualquer classe através da classe interna pública Point

Embora alguns livros de Java digam que as classes internas não pública somente são acessíveis à classe dentro da qual foram declaradas, isto não acontece na prática. A codificação bytecode (codificação para a qual são compilados os programas em Java) não implementa o conceito de classes internas. Desta forma, o compilador traduz as classes internas para classes comuns, acessíveis por qualquer outra classe do mesmo pacote. Como já vimos no item “Não usar o escopo de pacote para proteger a classe contra acessos indesejados”, esta proteção não é adequada.

Esta conversão torna a situação ainda mais complicada se a classe externa (aquela que contém a classe interna) tiver atributos ou métodos privados. Como a classe interna, que deve ter acesso a estes atributos e métodos, teve de ser traduzida como uma classe comum do mesmo pacote, o compilador (sem nenhum aviso) transforma os campos declarados como private em campos de acesso restrito ao pacote. Em versões mais recentes da plataforma Java, compilador não muda a declaração das variáveis, mas cria novos métodos que permitem o acesso aos campos privados da classe. Como vimos no item “Não usar o escopo de pacote para proteger a classe contra acessos indesejados”, estes campos não estarão protegidos adequadamente. A única maneira de evitar estes problemas é evitar o uso de classes internas.

Java permite também a declaração de classes internas anônimas, muito usadas para implementar tratamento de eventos em interfaces gráficas com o usuário. O uso destas classes internas também apresenta os problemas descritos acima e também deve ser evitado. Abaixo temos um exemplo de tratamento de eventos com classes internas anônimas:

//Um exemplo de uso de classe interna anônima.
public class MyClass extends Applet {
  ...
  someObject.addMouseListener(new MouseAdapter() {
    public void mouseClicked(MouseEvent e) {
      //código da classe...
    }
  });
  ...
  }
}

Neste caso, a desenvolvedor deveria ter criado uma nova classe para estender MouseAdapter e usado esta nova classe criada como parâmetro para addMouseListener(), conforme mostrado abaixo:

// eliminando a classe interna anônima
class MyAdapter extends MouseAdapter {
  public void mouseClicked(MouseEvent e) {
    //implementação do listener...
  }
}

// classe original adaptada
public class MyClass extends Applet {
  ...
  someObject.addMouseListener(new MyAdapter());
  ...
}

Comments