¿Se garantiza Java a las constantes de cadena en línea si se pueden determinar en tiempo de comstackción?

Considera este caso:

public Class1 { public static final String ONE = "ABC"; public static final String TWO = "DEF"; } public Class2 { public void someMethod() { System.out.println(Class1.ONE + Class1.TWO); } } 

En general, es de esperar que el comstackdor incorpore las constantes ONE y TWO. Sin embargo, ¿este comportamiento está garantizado? ¿Puede implementar en tiempo de ejecución Class2 sin Class1 en el classpath, y esperar que funcione independientemente de los comstackdores, o es una optimización de comstackdor opcional?

EDITAR: ¿Por qué demonios haces esto? Bueno, tengo una constante que se compartiría entre dos extremos de una aplicación (cliente y servidor sobre RMI) y sería muy conveniente en este caso particular poner la constante en una clase que solo puede estar en un lado de esa división ( ya que lógicamente es el que posee ese valor constante) en lugar de tenerlo en una clase de constantes arbitrarias solo porque necesita ser compartida por ambos lados del código. En tiempo de comstackción es todo un conjunto de archivos de origen, pero en tiempo de comstackción se divide por paquete.

Se garantiza que se tratará como una expresión constante, y se garantiza que será internado por la sección 15.28 de JLS :

Una expresión constante de tiempo de comstackción es una expresión que denota un valor de tipo primitivo o una cadena que no se completa abruptamente y se compone solo con lo siguiente:

  • Literales de tipo primitivo y literales de tipo Cadena (§3.10.5)
  • Lanza a tipos y moldes primitivos para escribir String
  • Los operadores unarios +, -, ~ y! (pero no ++ o -)
  • Los operadores multiplicativos *, / y%
  • Los operadores aditivos + y –

Las constantes de tiempo de comstackción de tipo String siempre se “internan” para compartir instancias únicas, utilizando el método String.intern.

Ahora, eso no dice que esté garantizado. Sin embargo, la sección 13.1 de la especificación dice:

Las referencias a los campos que son variables constantes (§4.12.4) se resuelven en tiempo de comstackción al valor constante que se denota. No debe haber ninguna referencia a dicho campo constante en el código en un archivo binario (excepto en la clase o interfaz que contiene el campo constante, que tendrá código para inicializarlo), y tales campos constantes siempre deben aparecer como inicializados; el valor inicial predeterminado para el tipo de dicho campo nunca se debe observar.

En otras palabras, incluso si la expresión en sí misma no fuera una constante , no debería haber ninguna referencia a Class1 . Entonces sí, estás bien. Eso no garantiza necesariamente que el valor concatenado se use en el bytecode, pero los bits a los que se hace referencia anteriormente garantizan que el valor concatenado esté internado, por lo que me sorprendería enormemente si no se alineara el valor concatenado. Incluso si no lo hace, tiene la garantía de que funcionará sin Class1 .

Comstackr eso con javac 1.6.0_14 produce el siguiente bytecode:

 public void someMethod(); Code: 0: getstatic #2; //Field java/lang/System.out:Ljava/io/PrintStream; 3: ldc #3; //String ABCDEF 5: invokevirtual #4; //Method java/io/PrintStream.println:(Ljava/lang/String;)V 8: return 

Por lo tanto, las cadenas se concatenan en tiempo de comstackción y el resultado se incluye en el conjunto constante de Class2.

No será indicado por el comstackdor, sino por el intérprete en tiempo de ejecución y, si es posible, convertido en código ensamblador.

No se puede garantizar, porque no todos los intérpretes (JVM) funcionan de la misma manera. Pero las implementaciones más importantes servirán.

Lamentablemente, no tengo un enlace para sustentar esto 🙁

Sospecho, pero no estoy seguro, que esto funcionará, pero no parece una buena idea.

Las formas “normales” de hacer esto son:

  1. Coloque las constantes en un paquete compartido entre el cliente y el servidor. Presumiblemente, existe tal paquete, porque ahí es donde van las interfaces.
  2. Si no hay tal paquete, cree 2 clases con las constantes compartidas: una para el servidor y otra para el cliente.

Ver JLS 13.4.9 . Si bien no requiere explícitamente que el comstackdor inline las constantes, sugiere que la comstackción condicional y el soporte para las constantes en las sentencias switch hacen que el comstackdor siempre tenga constantes en línea.

Parece que estás codificando tu propia versión de la capacidad incorporada en enum , que hace public static final para ti, nombrando correctamente a través de name() y toString() (además de tener algunas otras ventajas, pero quizás con la desventaja de una huella de memoria más grande).

¿Estás usando una versión anterior de Java que aún no incluye enum?