Los valores finales estáticos de Java se reemplazan en el código al comstackr?

En java, decir que tengo lo siguiente

==fileA.java== class A { public static final int SIZE = 100; } 

Luego en otro archivo utilizo este valor

 ==fileB.java== import A; class b { Object[] temp = new Object[A.SIZE]; } 

Cuando esto se comstack, SIZE se reemplaza con el valor 100, de modo que si tuviera que reemplazar el archivo FileA.jar pero no FileB.jar, la matriz de objetos obtendría el nuevo valor o se codificaría en 100 porque eso es cierto. el valor cuando se construyó originalmente?

Gracias,
Stephanie

Sí, el comstackdor Java reemplaza los valores constantes estáticos como SIZE en su ejemplo con sus valores literales.

Por lo tanto, si más adelante modificas SIZE en la clase A pero no recomstacks la clase b , aún verás el valor anterior en la clase b . Puedes probar esto fácilmente:

archivo A.java

 public class A { public static final int VALUE = 200; } 

archivo B.java

 public class B { public static void main(String[] args) { System.out.println(A.VALUE); } } 

Comstack A.java y B.java. Ahora ejecuta: java B

Cambie el valor en A.java. Recompile A.java, pero no B.java. Ejecuta nuevamente y verás que se imprime el valor anterior.

Puede evitar que la constante se compile en B, haciendo

 class A { public static final int SIZE; static { SIZE = 100; } } 

Otra ruta para probar que el comportamiento es mirar el bytecode generado. Cuando la constante es “pequeña” (presumiblemente <128):

 public B(); Code: 0: aload_0 1: invokespecial #10; //Method java/lang/Object."":()V 4: aload_0 5: bipush 42 7: anewarray #3; //class java/lang/Object 10: putfield #12; //Field temp:[Ljava/lang/Object; 13: return } 

(Usé 42 en lugar de 100, por lo que se destaca más). En este caso, está claramente sustituido en el código de bytes. Pero, di que la constante es “más grande”. Luego obtienes un código de bytes que se ve así:

 public B(); Code: 0: aload_0 1: invokespecial #10; //Method java/lang/Object."":()V 4: aload_0 5: ldc #12; //int 86753098 7: anewarray #3; //class java/lang/Object 10: putfield #13; //Field temp:[Ljava/lang/Object; 13: return 

Cuando es más grande, se utiliza el código de operación “ldc”, que según la documentación de JVM “es un byte sin signo que debe ser un índice válido en el conjunto de la constante de tiempo de ejecución de la clase actual”.

En cualquier caso, la constante está incrustada en B. Imagino, dado que en los códigos de operación solo se puede acceder al conjunto de constantes de tiempo de ejecución de las clases actuales, que la decisión de escribir la constante en el archivo de clase es independiente de la implementación (pero no lo hago). lo sé por hecho).

Woo – ¡aprendes algo nuevo todos los días!

Tomado de la especificación de Java …

Nota: Si un tipo primitivo o una cadena se define como una constante y el valor se conoce en tiempo de comstackción, el comstackdor reemplaza el nombre de la constante en todas partes del código con su valor. Esto se llama una constante de tiempo de comstackción. Si el valor de la constante en el mundo exterior cambia (por ejemplo, si está legislado que pi en realidad debería ser 3.975), necesitará recomstackr cualquier clase que use esta constante para obtener el valor actual.

El concepto importante aquí es que el campo static final se inicializa con una constante en tiempo de comstackción , como se define en el JLS. Use un inicializador no constante (o no static o no final ) y no se copiará:

 public static final int SIZE = null!=null?0: 100; 

( null no es una * constante de tiempo de comstackción`).

En realidad me encontré con esta extrañeza hace un tiempo.

Esto comstackrá “100” en la clase b directamente. Si solo recomstack la clase A, esto no actualizará el valor en la clase B.

Además de eso, el comstackdor puede no darse cuenta de recomstackr la clase b (en el momento en que estaba comstackndo directorios individuales y la clase B estaba en un directorio separado y comstackr un directorio no desencadenó una comstackción de B)

Como una optimización, el comstackdor alineará esa variable final .

Entonces en tiempo de comstackción se verá así.

 class b { Object[] temp = new Object[100]; } 

Una cosa que debe tenerse en cuenta es que: el valor final estático se conoce en tiempo de comstackción si el valor no se conoce en tiempo de comstackción, el comstackdor no reemplazará el nombre de la constante en todas partes del código con su valor.

  public class TestA { // public static final int value = 200; public static final int value = getValue(); public static int getValue() { return 100; } } public class TestB { public static void main(String[] args) { System.out.println(TestA.value); } } 

primero comstack TestA y TestB, ejecuta TestB

luego cambie TestA.getValue () para devolver 200, compile TestA, ejecute TestB , TestB obtendrá el nuevo valor enter image description here

Hay una excepción a esto:

Si el campo final estático es nulo en el momento de la comstackción, entonces no se reemplaza por nulo (que en realidad es su valor)

A.java

 class A{ public static final String constantString = null; } 

B.java

 class B{ public static void main(String... aa){ System.out.println(A.constantString); } } 

Comstack tanto A.java como B.java y ejecuta Java B

La salida será nula


Ahora actualiza A.java con el siguiente código y comstack solo esta clase.

 class A{ public static final String constantString = "Omg! picking updated value without re-comstacktion"; } 

Ahora ejecuta java B

La salida será Omg! seleccionando valor actualizado sin recomstackción

Java optimiza estos tipos de valores, pero solo si están en la misma clase. En este caso, la JVM busca en A.SIZE en lugar de optimizarla debido al caso de uso que está considerando.