¿Se garantiza Java a las constantes de cadena en línea si se pueden determinar en el momento de la compilación?

StackOverflow https://stackoverflow.com/questions/1406616

  •  05-07-2019
  •  | 
  •  

Pregunta

Considere 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);
  }
}

Normalmente, se esperaría que el compilador incorpore las constantes ONE y TWO. Sin embargo, ¿está garantizado este comportamiento? ¿Se puede implementar en tiempo de ejecución Class2 sin Class1 en la ruta de clase, y esperar que funcione independientemente de los compiladores, o se trata de una optimización de compilador opcional?

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

¿Fue útil?

Solución

Se garantiza que se tratará como una expresión constante y se garantiza que se internará en sección 15.28 del JLS :

  

Una expresión constante en tiempo de compilación es   una expresión que denota un valor de   tipo primitivo o una cadena que hace   No se completa abruptamente y se compone   utilizando solo lo siguiente:

     
      
  • Literales de tipo primitivo y literales de tipo String (& # 167; 3.10.5)
  •   
  • Se convierte a tipos primitivos y se convierte en tipo String
  •   
  • Los operadores unarios +, -, ~, y! (pero no ++ o -)
  •   
  • Los operadores multiplicativos *, / y%
  •   
  • Los operadores aditivos + y -
  •   
  • ...
  •   

...

  

Constantes de tiempo de compilación de tipo String   Siempre están " internados " para compartir   Instancias únicas, utilizando el método.   String.intern.

Ahora, eso no dice que esté garantizado para estar en línea. Sin embargo, la sección 13.1 de la especificación dice:

  

Referencias a campos que son constantes   las variables (& # 167; 4.12.4) se resuelven en   Tiempo de compilación al valor constante.   que se denota No hay referencia a tal   un campo constante debe estar presente en   El código en un archivo binario (excepto en   la clase o interfaz que contiene el   Campo constante, que tendrá código.   Inicializarlo, y tal constante.   los campos siempre deben aparecer que han sido   inicializado el valor inicial por defecto   para el tipo de tal campo debe   nunca ser observado.

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

Otros consejos

Compilar 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 compilación y el resultado se incluye en el grupo constante de Class2.

El compilador no lo integrará sino el intérprete en tiempo de ejecución y, si es posible, lo convertirá en código de ensamblaje.

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

Lamentablemente, no tengo un enlace para mantener esto :(

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

El " normal " Las formas de hacer esto son:

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

Consulte JLS 13.4.9 . Si bien no requiere explícitamente que las constantes estén integradas por el compilador, sugiere que la compilación condicional y el soporte para las constantes en las declaraciones de switch hacen que el compilador siempre tenga constantes en línea.

Parece que está codificando su propia versión de la capacidad incorporada en enum , que hace public static final para usted, nombre apropiado a través de name ( ) y toString () (además de tener algunas otras ventajas, pero quizás tener la desventaja de una mayor huella de memoria).

¿Está utilizando una versión anterior de Java que aún no incluye enumeración?

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top