Estou com uma dúvida sobre classes interna de método.Se alguém pode me ajudar eu agradeço.A dúvida é a seguinte:
O livro que eu estou lendo faz a seguinte afirmação: Um objeto da classe interna não poderá usar as variáveis locais do método onde a classe interna estiver, pois, as variavéis locais do método residem na pilha e só existem conforme a duração do método.A menos que as variavéis locais sejam marcadas como finais.
1 - Eu não entendi porque uma variavel marcada como final pode ser acessada por um objeto da classe interna de método.
2 - O que muda entre uma variavel sem o modificado final e com o modificador final, além, de não permitir alterar o valor?.
3 - Se marcada com final ela deixa de residir na pilha?
Ela pode ser acessada porque internamente o compilador consegue obter o valor dessa variável “final”. Um exemplo:
classObjeto{privateStringnome;publicObjeto(StringpNome){nome=pNome;}publicStringtoString(){returnnome;}}classTesteClasseInternaFinal{publicstaticvoidmain(String[]args){finalObjetofin=newObjeto("Obscuridade");classInterna{publicStringteste(){returnfin.toString();}}Internainte=newInterna();System.out.println(inte.teste());// deve imprimir "Obs"}}
O compilador transforma isso em 3 classes (Objeto.class, TesteClasseInternaFinal.class e TesteClasseInternaFinal$1Interna.class). Se descompilarmos TesteClasseInternaFinal$1Interna.class e TesteClasseInternaFinal.class, ela é equivalente ao seguinte código Java:
classTesteClasseInternaFinal$1Interna{// gerado pelo compiladorfinalObjetoval$fin;// gerado pelo compiladorpublicTesteClasseInternaFinal$1Interna(Objetoobj){val$fin=obj;super();}publicStringteste(){// repare que trocou "fin" por "val$fin", campo gerado pelo compiladorreturnval$fin.toString();}}classTesteClasseInternaFinal{publicTesteClasseInternaFinal(){super();}publicstaticvoidmain(String[]args){finalObjetofin=newObjeto("Obscuridade");// note que trocou "Interna inte = new Interna()" por um outro construtor// que inclui o tal objeto "final" TesteClasseInternaFinal$1Internainte=newTesteClasseInternaFinal$1Interna(fin);System.out.println(inte.teste());// deve imprimir "Obs"}}
Isso foi definido porque só dessa maneira é que dá para passar o valor para esse novo “construtor” gerado pelo compilador. É mais uma definição; o pessoal da Sun não precisaria obrigatoriamente ter feito essa restrição (só que o código gerado seria bem mais complicado que já é)
Não. A única diferença é que é usado o truque de compilação acima.
T
thingol
Para o exemplo, eu tive de criar um objeto de uma classe que não é String ou então um tipo primitivo.
Para String ou tipos primitivos, definir uma variável como final ativa algumas otimizações que em resumo acabam não criando esse campo (val$<nome da variável local final>) nem esse construtor mágico com mais um parâmetro.
L
Lintz_net
Pow cara, eu entendi +ou- a sua explicação muito boa por sinal, mas foi o suficiente para entender…Lembrou-me muito gabiarra(hahaha) mas tudo bem.
Não vou ficar tentando entender essas implementações da sun. Vou só decorar que uma variavel local marcada como final pode ser recuperada numa classe interna de método.
Obrigado pela explicação.
T
thingol
O problema de usar uma variável local que não é “final” em uma classe interna está relacionado com o seguinte problema: se ela não fosse “final” e essa classe interna na verdade fosse uma thread*, você poderia ter o caso em que o valor da variável local é diferente do valor que o código da classe interna está executando. Como eles não quiseram correr o risco, então forçaram a barra e definiram que deveria ser “final”.
É possível gerar código que não impõe que seja “final”, mas nesse caso seria bastante complicado gerar o código (diferentemente da “gambiarra” que é possível ao se usar “final”).
Ou seja, se isto fosse possível (sem usar o “final”):
Objetoobjeto=newObjeto("isto");newThread(newRunnable(){// aqui a "classe interna" aparece "disfarçada"publicvoidrun(){System.out.println(objeto);}}).start();objeto=newObjeto("aquilo");
L
Lintz_net
Thigol, obrigado pela explicação.Ficou bem claro o motivo e a solução que a sun escolheu para esta “gambiarra” rsrs
Omeganosferatu
Thingol você descompilou os códigos pra ver isso ou foi de muringa ??? Poots show de bola a explicação, quanto mais eu frequento o GUJ mais eu vejo que tenho que estudar muito ainda
T
thingol
É claro que descompilei o código. Não sei se isso está documentado em algum lugar. (Minha cabeça não consegue guardar coisas que toda hora estão mudando; se não tiver acesso à Internet fico imediatamente burro e estúpido.)