java - Relacionado con el internado de cuerdas
string string-interning (4)
Aunque esté utilizando el método intern()
, debe recordar que ==
compara por referencia y no por valor.
Así que en los casos de
System.out.println(c=="Hel"+a);
System.out.println(c=="Hel"+d);
System.out.println(c=="Hel"+b);
"Hel" + a
o "Hel" + d
o "Hel" + b
tendrá una nueva referencia en la memoria que no es igual a la de c
.
en el caso final, ya que el valor de la cadena es final, la evaluación se realiza en tiempo de compilación en lugar de tiempo de ejecución como optimización, ya que nunca cambiará. Además, si está pensando cuando define una cadena literal, Java los coloca internamente.
public static void main(String[] args) {
String a = new String("lo").intern();
final String d = a.intern();
String b = "lo";
final String e = "lo";
String c = "Hello";
System.out.println(b==a);//true
System.out.println(d==a);//true
System.out.println(e==a);//true
System.out.println(c=="Hel"+a); //why is this false? when e==a is true
System.out.println(c=="Hel"+d); //why is this false?
System.out.println(c=="Hel"+b); //why is this false?
System.out.println(c=="Hel"+e); //this is true
}
Esto resulta en
true
true
true
false
false
false
true
La expresión e==a
es verdadera implica la misma referencia. Entonces, ¿por qué la última expresión es verdadera pero la cuarta es la última, es decir, c== "Hel"+a
es falsa?
La expresion
"Hel" + a
No es una constante de tiempo de compilación. En realidad, se compila a:
new StringBuilder().append("Hel").append(a).toString()
(o similar) que crea un nuevo objeto String en tiempo de ejecución.
Sin embargo, debido a que e
es final, el compilador puede determinar que la concatenación de "Hel"
y el valor de e es un valor constante, y así lo internan.
todas estas cadenas se calculan en tiempo de ejecución, es por eso que son diferentes
System.out.println(c=="Hel"+a); //why is this false? when e==a is true
System.out.println(c=="Hel"+d); //why is this false?
System.out.println(c=="Hel"+b); //why is this false?
este calculado durante el tiempo de compilación, porque e es final:
System.out.println(c=="Hel"+e); //this is true
Si cambia el código a esto:
System.out.println(c==("Hel"+a).intern()); //why is this false? when e==a is true
System.out.println(c==("Hel"+d).intern()); //why is this false?
System.out.println(c==("Hel"+b).intern()); //why is this false?
todos ellos producirán verdad
El compilador Java ( javac
) traduce su código en Java a un código de bytes que ejecuta la JVM . También hace algunas optimizaciones para ti. Puede verificar el código de byte generado usando la utilidad javap
con el parámetro -c
Concatenación con cuerda final
c==a
es verdadero porque c
es final
Aquí está el código de byte para este fragmento (solo la última comparación):
public static void main(java.lang.String[]);
Code:
0: ldc #2; //String Hello
2: astore_2
3: getstatic #3; //Field java/lang/System.out:Ljava/io/PrintStream;
6: aload_2
7: ldc #2; //String Hello
9: if_acmpne 16
12: iconst_1
13: goto 17
16: iconst_0
17: invokevirtual #4; //Method java/io/PrintStream.println:(Z)V
20: return
}
Como puedes ver, el compilador java ha fusionado el "Hel" con "lo" y solo compara dos cadenas de caracteres "Hola". Java interns cadena literales de forma predeterminada - es por eso que devuelve true
Concatenación con cuerda no final
Si está concatenando el literal de cadena con una variable de cadena no final , el código de byte será diferente:
public static void main(java.lang.String[]);
Code:
0: ldc #2; //String lo
2: astore_1
3: ldc #3; //String Hello
5: astore_2
6: getstatic #4; //Field java/lang/System.out:Ljava/io/PrintStream;
9: aload_2
10: new #5; //class java/lang/StringBuilder
13: dup
14: invokespecial #6; //Method java/lang/StringBuilder."<init>":()V
17: ldc #7; //String Hel
19: invokevirtual #8; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
22: aload_1
23: invokevirtual #8; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
26: invokevirtual #9; //Method java/lang/StringBuilder.toString:()Ljava/lang/String;
29: if_acmpne 36
32: iconst_1
33: goto 37
36: iconst_0
37: invokevirtual #10; //Method java/io/PrintStream.println:(Z)V
40: return
}
Aquí estamos comparando el resultado de java/lang/StringBuilder.toString:()Ljava/lang/String;
Método que obviamente devuelve otro objeto: es igual a "Hola" por valor pero no por referencia
Puede encontrar más detalles sobre la comparación de cadenas en esta pregunta de