Pessoal, relendo o livro K&B no capítulo 8 - Inner Class me deparei com uma questão.
É dito que uma Local-Method Inner Class não pode acessar Local Variables, pois as variáveis morreriam com o Stack e se houvese uma referência da Local-Variable Inner Class a variável local poderia causar problemas se estivese morta!
Entretanto é possível acessar uma marcada como final. Por que isso ocorre já qeu uma final também vai morrer com o Stack.
Por acaso seria porque se pode fazer uma cópia de uma constante com maior segurança ?
[quote]Because the local variables aren’t guaranteed to be alive as long
as the method-local inner class object, the inner class object can’t use them.[/quote]
Como seria liberada uma variável local se a classe interna anônima estiver usando a mesma?
Pois eh mateusbrum… procurei a resposta no meu livro de certificação da AltaBooks e eles só falam que pode, mas não falam o porquê.
Eu só sei o seguinte. Classes internas de método, apesar de tudo, guardam seus objetos no heap pois pode ter alguma referencia pro objeto que esteja fora do método. Logo não poderia utilizar variáveis locais que sumirão junto com a pilha.
Então, apesar de não ter achado nada a respeito, só vejo duas hipóteses:
1 - variáveis locais “final” não ficam na pilha e ficam no heap ou em algum outro lugar distante da JVM que eu desconheço… rsrsrs (acho pouco provável).
2 - na hora da compilação, o compilador substitui chamadas para variaveis locais final por seus valores literais com o intuito de aumentar a performance (já li algo do tipo, ele faz várias coisas similares pra melhorar a performance)… acho que deve ser isso.
Ou seja, se declarou “final int x = 5” e usou no método “valor = x”, o compilador deve substituir por “valor = 5”, e a chamada é removida.
Porém, se descobrir ao certo em alguma especificação da sun posta ae !!
Só completando o que foi explicado no JavaRanch.
Veja o exemplo abaixo:
class TesteInnerClass {
public static void main(String[] args) {
final Long hello = new Long (1234567L);
class MinhaClasse {
private String msg;
public MinhaClasse (String msg) {
this.msg = msg;
}
public String printHello () {
return msg + " -> " + hello.toString();
}
}
MinhaClasse mc = new MinhaClasse ("Alo, mundo!");
System.out.println (mc.printHello());
}
}
é transformada pelo compilador em:
// Note que "inner classes" dentro de métodos são traduzidas para algo como:
// nome da classe externa + "$" + algum número + nome da classe interna
class TesteInnerClass$1MinhaClasse {
// Criada uma variável que é uma cópia da variável "final" local
final Long val$hello;
// O construtor original é
public TesteInnerClass$1MinhaClasse(String msg, Long val$hello) {
this.msg = msg;
this.val$hello = val$hello;
}
}
class TesteInnerClass {
public static void main(String[] args) {
final Long hello = new Long (1234567L);
TesteInnerClass$1MinhaClasse mc = new TesteInnerClass$1MinhaClasse ("Alo, mundo!", hello);
System.out.println (mc.printHello());
}
}
Se a variável não fosse "final", seu valor poderia estar alterado quando fôssemos chamar "printHello".
(Seria teoricamente possível não exigir que a variável não fosse "final" mas a implementação seria muito mais complexa que a acima. )