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