java string string-interning

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