segunda-feira, 12 de agosto de 2013

Por que preciso declarar como final variáveis passadas à classes anônimas (inner class)?

É muito comum quando estamos desenvolvendo interfaces gráficas seja em Swing ou Android o uso de classes anônimas, geralmente usamos classes anônimas como callbacks em listeners de eventos. Devido às características do Java, quando precisamos de um callback passamos uma instância de classe como parâmetro ao invés de simples funções como podemos fazer em Javascript por exemplo.

Repare que no código acima temos um erro, pois tentamos acessar a variável "content" dentro de uma inner class. Para resolver o problema é simples, basta declararmos "content" como final.

Para entender porque devemos declarar variáveis a serem acessadas em inner classes como final, devemos primeiro entender como inner classes são traduzidas em byte code.

Quando temos uma inner class ela não é gerada no mesmo arquivo de byte code da classe que a contém (outer class), são gerados dois arquivos, um com a outer class e outro com a inner class:

Classe1.class
Classe1$OnClickListener.class

Aqui surge um problema, nossa classe Classe1$OnClickListener.class precisa acessar a variável "content" declarada em Classe1.class. Para que isso seja possível o compilador cria em Classe1$OnClickListener.class um atributo que recebe uma cópia do valor da variável da outer class. Mas imagine que por algum motivo a variável em Classe1.class ou mesmo o atributo em Classe1$OnClickListener.class tenha seu valor alterado, teriamos um problema de sincronização de dados. Para evitar este problema somos obrigados a declararmos as variáveis que serão usadas em inner classes como final, assim os valores tanto nas outer classes e inner classes serão iguais.

Referências:

  • http://stackoverflow.com/questions/7423028/java-local-variable-visibility-in-anonymous-inner-classes-why-is-final-keywo
  • http://techtracer.com/2008/04/14/mystery-of-accessibility-in-local-inner-classes/


Nenhum comentário:

Postar um comentário