Java cadena de concatenación e internamiento
string-concatenation string-interning (3)
De documentos internos ()
Todas las cadenas literales y expresiones constantes con valores de cadena están internados. Los literales de cadena se definen en la sección 3.10.5 de la Especificación del lenguaje Java ™.
Y de JLS 3.10.5
- Las cadenas calculadas por expresiones constantes (§15.28) se calculan en tiempo de compilación y luego se tratan como si fueran literales.
- Las cadenas calculadas por concatenación en tiempo de ejecución se crean recientemente y, por lo tanto, son distintas.
Su cadena b1 no está realmente internada. De ahí la diferencia.
Pregunta 1
String a1 = "I Love" + " Java";
String a2 = "I Love " + "Java";
System.out.println( a1 == a2 ); // true
String b1 = "I Love";
b1 += " Java";
String b2 = "I Love ";
b2 += "Java";
System.out.println( b1 == b2 ); // false
En el primer caso, entiendo que es una concatenación de dos literales de cadena, por lo que el resultado "Amo Java" se internará, dando el resultado verdadero. Sin embargo, no estoy seguro sobre el segundo caso.
Pregunta 2
String a1 = "I Love" + " Java"; // line 1
String a2 = "I Love " + "Java"; // line 2
String b1 = "I Love";
b1 += " Java";
String b2 = "I Love ";
b2 += "Java";
String b3 = b1.intern();
System.out.println( b1 == b3 ); // false
Lo anterior devuelve falso, pero si comento las líneas 1 y 2, devuelve verdadero. ¿Porqué es eso?
La primera parte de su pregunta es simple: el compilador de Java trata la concatenación de múltiples literales de cadena como un solo literal de cadena, es decir
"I Love" + " Java"
y
"I Love Java"
son dos literales de cadena idénticos, que se internan correctamente.
El mismo comportamiento interno no
se
aplica a la operación
+=
en cadenas, por lo que
b1
y
b2
se construyen realmente en tiempo de ejecución.
La segunda parte es más complicada.
Recuerde que
b1.intern()
puede devolver
b1
o algún otro objeto
String
que sea igual a él.
Cuando mantiene
a1
y
a2
, recupera
a1
de la llamada a
b1.intern()
.
Cuando
b1.intern()
a1
y
a2
, no hay una copia existente para devolver, por lo que
b1.intern()
te devuelve
b1
.
Respuesta a la pregunta 1:
No puede comparar dos cadenas con
==
.
El
==
compara dos tipos de datos primitivos (int, long, float, double y boolean) o
referencias de
objeto.
Lo que significa que si las varibales de referencia (a1, a2, b1, b2) no tienen la misma referencia (lo que significa que no apuntan al mismo objeto en la memoria), no son iguales (comparación con
==
).
Si compararas con
b1.equals(b2)
, la expresión sería verdadera ya que los datos del objeto son los mismos.
En el primer caso, Java es lo suficientemente inteligente como para concatenar las cadenas antes de asignarles algo de memoria (incluso antes de la compilación), lo que significa que ambas cadenas se almacenan en la misma dirección.
Por lo tanto, las variables a1 y a2 hacen referencia al mismo objeto y son iguales (
==
).
En el segundo caso, primero asigna a las variables un valor diferente (a diferencia del primer caso).
Esto significa que obtienen una dirección separada en la memoria.
Incluso si cambia el valor para que sean iguales, la dirección no cambia y una comparación con
==
evalúa como falsa.
Esto sucede durante el tiempo de ejecución.
En cuanto a la pregunta 2: @dasblinkenlight ya dio una buena respuesta a eso.