Vejamos o seguinte código:
public class Foo{ public static final int a = 10; } public class Bar{ public static void main(String[] args){ System.out.println(Foo.a); } }
Se compilarmos e rodarmos o resultado será 10.
O que vai acontecer se alterarmos o valor da variável i para 30 e compilarmos somente a class Foo?
Se rodarmos a classe Bar veremos que ainda assim o resultado será 10.
Isso acontece por que ao compilarmos nosso código, as *constantes são substituídas pelo seus valores literais, ou seja, no bytecode da classe Bar, não existe referencia pra classe Foo, na verdade, dentro do System.out.println estará escrito o literal 10.
Podemos verificar isso executando o comando javap -c:
class Um extends java.lang.Object{
Um();
Code:
0: aload_0
1: invokespecial #1; //Method java/lang/Object."<init>":()V
4: return
public static void main(java.lang.String[]);
Code:
0: getstatic #2; //Field java/lang/System.out:Ljava/io/PrintStream;
3: bipush 10
5: invokevirtual #3; //Method java/io/PrintStream.println:(I)V
8: return
}
*Várias regras devem ser avaliadas para considerarmos uma variável uma constante, mas resumindo, o seu valor deve ser conhecido em tempo de compilação.
Como no exemplo abaixo:
public class Valor { final int compilacao = 1; final int execucao; public Valor(int execucao) { this.execucao = execucao; } public static void main(String[] args) throws SecurityException, NoSuchFieldException, IllegalArgumentException, IllegalAccessException { Valor valor = new Valor(2); System.out.println(valor.compilacao);// aqui imprime 1 System.out.println(valor.execucao);// aqui imprime 2 Field fieldCompilacao = Valor.class.getDeclaredField("compilacao"); Field fieldExecucao = Valor.class.getDeclaredField("execucao"); fieldCompilacao.setAccessible(true); fieldExecucao.setAccessible(true); fieldCompilacao.set(valor, 10); fieldExecucao.set(valor, 20); System.out.println(valor.compilacao);// aqui deveria imprimir 10 mas imprime 1 System.out.println(valor.execucao);// aqui imprime 20 } }
Perceba que o valor da variável "compilacao" é conhecido em tempo de compilação, portanto, no bytecode ela será substituída por seu valor literal, já a variável "execucao" só é conhecida em tempo de execução (no momento de criação do objeto).
Com isso em mente percebi o que estava errando na minha biblioteca de cópia de objetos. Existe uma grande diferença entre algo constante e algo imutável. Para efeitos de testes criei algumas classes com atributos final e sem perceber inicializei esses valores "inline", tornando seu valores conhecidos em tempo de compilação, portanto, constantes. Não vejo muito sentido alterar valores de constantes, a final, são constantes!!
Agora devo trabalhar nesse sentido, copia de objetos, sejam eles imutáveis ou não, deixando de lado as constantes.
Quem quiser conhecer a biblioteca, está no link abaixo:
https://github.com/geraldox100/copyobject
Referências:
http://docs.oracle.com/javase/specs/jls/se7/html/jls-13.html#jls-13.4.9
http://www.javaworld.com/javaqa/2003-03/02-qa-0328-constant.html
http://www.coderanch.com/t/454384/java/java/compile-time-constant
Nenhum comentário:
Postar um comentário