java string final

¿Cómo se realiza la concatenación de cadenas finales en Java?



string (1)

Cuando compilo este fragmento.

public class InternTest { public static void main(String...strings ){ final String str1="str"; final String str2="ing"; String str= str1+str2; } }

Que produce el siguiente código de byte

public static void main(java.lang.String...); flags: ACC_PUBLIC, ACC_STATIC, ACC_VARARGS Code: stack=1, locals=4, args_size=1 0: ldc #16 // String str 2: astore_1 3: ldc #18 // String ing 5: astore_2 6: ldc #20 // String string 8: astore_3 9: return

por lo tanto, la cadena "cadena" literal ya está allí en el conjunto constante que se inserta 6: ldc #20 // String string en la pila en esta línea.

Cotizando JSL

De JLS §4.12.4 - Variables finales:

Una variable de tipo primitivo o tipo String, que es final e inicializa con una expresión de constante de compilación (§15.28), se denomina variable constante.

También de JLS §15.28 - ConstantExpression:

Las expresiones constantes en tiempo de compilación de tipo Cadena siempre se "internan" para compartir instancias únicas, utilizando el método Cadena # intern ().

Así que sé que str1 y str2 se internarán en el momento en que se haya creado. "Str" y "ing" compartirán la misma memoria en la línea String str= str1+str2; Pero cómo str1 + str2 produce directamente "cadena" en el conjunto de cadenas constantes. Sin invocar ninguna clase de generador de cadenas como lo hace cuando no escribo final . ? Para ver si tiene algo que ver con cosas internas.

Escribí este fragmento

public class IntermTest { public static void main(String...strings ){ String str1=("str").intern(); String str2=("ing").intern(); String str= str1+str2; } }

Pero cuando generé el código byte obtuve este

public static void main(java.lang.String...); flags: ACC_PUBLIC, ACC_STATIC, ACC_VARARGS Code: stack=3, locals=4, args_size=1 0: ldc #16 // String str 2: invokevirtual #18 // Method java/lang/String.intern: ()Ljava/lang/String; 5: astore_1 6: ldc #24 // String ing 8: invokevirtual #18 // Method java/lang/String.intern: ()Ljava/lang/String; 11: astore_2 12: new #26 // class java/lang/StringBuilder 15: dup 16: aload_1 17: invokestatic #28 // Method java/lang/String.valueOf :(Ljava/lang/Object;)Ljava/lang/String; 20: invokespecial #32 // Method java/lang/StringBuilder. "<init>":(Ljava/lang/String;)V 23: aload_2 24: invokevirtual #35 // Method java/lang/StringBuilder. append:(Ljava/lang/String;)Ljava/lang/StringBuilder; 27: invokevirtual #39 // Method java/lang/StringBuilder. toString:()Ljava/lang/String; 30: astore_3 31: return

De hecho, también utiliza stringBuilder para la concatenación. Así que tiene que hacer algo con final. ¿Hay algo especial en las cuerdas final que definitivamente no conozco?


http://docs.oracle.com/javase/specs/jls/se8/html/jls-15.html#jls-15.28 dice que

Los nombres simples (§6.5.6.1) que se refieren a variables constantes (§4.12.4) son expresiones constantes.

http://docs.oracle.com/javase/specs/jls/se8/html/jls-15.html#jls-15.28 también dice:

Una expresión constante es una expresión que denota un valor de tipo primitivo o una cadena que no se completa de forma abrupta y se compone utilizando solo lo siguiente:

  • Literales de tipo primitivo y literales de tipo String (§3.10.1, §3.10.2, §3.10.3, §3.10.4, §3.10.5)
  • [...]
  • Los operadores aditivos + y - (§15.18)
  • [...]
  • Nombres simples (§6.5.6.1) que se refieren a variables constantes (§4.12.4).

Ejemplo 15.28-1. Expresiones constantes

[...]

"El entero" + Long.MAX_VALUE + "es muy grande".

Dado que esas dos variables son expresiones constantes, el compilador realiza la concatenación:

String str = str1 + str2;

se compila de la misma manera que

String str = "str" + "ing";

que se compila de la misma manera que

String str = "string";