java - tipo - El comportamiento de los literales String es confuso
tipos de variables en java ejemplos (11)
¡Finalmente sé la respuesta!
Lea la sección 15.21.3 de la especificación de Java SE 8. Operadores de igualdad de referencia == y! = ( http://docs.oracle.com/javase/specs/jls/se8/html/jls-15.html#jls-15.21.3 )
Mientras que == puede usarse para comparar referencias de tipo String, tal prueba de igualdad determina si los dos operandos se refieren o no al mismo objeto String.
El resultado es falso si los operandos son objetos de cadena distintos , incluso si contienen la misma secuencia de caracteres (§3.10.5). El contenido de dos cadenas s y t se puede probar para determinar la igualdad mediante el método invocation s.equals (t).
Entonces el siguiente código:
class Test {
public static void main(String[] args) {
String hello = "Hello";
String lo = "lo";
System.out.println((hello == ("Hel"+lo))); // line 3
}
}
Las declaraciones ("Hel" + lo) en la línea 3, devuelven las nuevas cadenas que se calcularon por concatenación en tiempo de ejecución .
* Las cadenas calculadas por concatenación en tiempo de ejecución son de nueva creación y, por lo tanto, distintas. ( http://docs.oracle.com/javase/specs/jls/se8/html/jls-3.html#d5e1634 )
Entonces el resultado de este código:
class Test {
public static void main(String[] args) {
String hello = "Hello";
String lo = "lo";
System.out.println((hello == ("Hel"+lo))); // line 3
}
}
podría resultar:
false
Porque,
El objeto "Hola" en esta declaración:
String hello = "Hello";
y ("Hel" + lo) objeto en esta declaración:
System.out.print((hello == ("Hel"+lo)) + " ");
es diferente , aunque:
* ambos contienen el mismo carácter de secuencia, que es "Hola".
* Ambos tienen el mismo código hash.
* hello.equals (("Hel" + lo)) devolverá true.
El comportamiento de los literales String es muy confuso en el siguiente código.
Puedo entender que la línea 1, la línea 2 y la línea 3 son true
, pero ¿por qué la línea 4 es false
?
Cuando imprimo el hashcode de ambos son los mismos.
class Hello
{
public static void main(String[] args)
{
String hello = "Hello", lo = "lo";
System.out.print((Other1.hello == hello) + " "); //line 1
System.out.print((Other1.hello == "Hello") + " "); //line 2
System.out.print((hello == ("Hel"+"lo")) + " "); //line 3
System.out.print((hello == ("Hel"+lo)) + " "); //line 4
System.out.println(hello == ("Hel"+lo).intern()); //line 5
System.out.println(("Hel"+lo).hashCode()); //hashcode is 69609650 (machine depedent)
System.out.println("Hello".hashCode()); //hashcode is same WHY ??.
}
}
class Other1 { static String hello = "Hello"; }
Sé que ==
verifica la igualdad de referencia y busca en el grupo de literales. Sé que equals()
es la forma correcta. Quiero entender el concepto.
Ya he comprobado esta question , pero no se explica claramente.
Agradecería una explicación completa.
Cada expresión constante en tiempo de compilación que sea de tipo String
se colocará en el grupo de cadenas.
Esencialmente, eso significa: si el compilador puede (fácilmente) "calcular" el valor de la String
sin ejecutar el programa, entonces se colocará en la agrupación (las reglas son un poco más complicadas que eso y tienen algunos casos de esquina, vea el enlace arriba para todos los detalles).
Eso es cierto para todas las cuerdas en las líneas 1-3.
"Hel"+lo
no es una expresión constante en tiempo de compilación, porque lo
es una variable no constante.
Los códigos hash son los mismos, porque el código hash de una cadena depende solo de su contenido . Eso es requerido por el contrato de equals()
y hashCode()
.
Como ya sabe ... esto es solo por referencia ... cuando la cadena proviene de la agrupación tendrá la misma referencia ... pero cuando se hacen las conversaciones de personal, se genera una nueva cadena con una nueva referencia ...
Puede consultar este enlace para agrupar el concepto
El hashCode no tiene nada que ver con una referencia de objetos (La comprobación == es un comparador de referencia). Es posible tener 2 objetos donde el código hash devuelve el mismo valor, el operador igual devuelve verdadero, pero == devuelve falso. Esto es cuando son 2 objetos diferentes, pero con el mismo valor.
Creo que la razón por la que la línea 4 devuelve falso es que es un valor calculado en tiempo de ejecución y, por lo tanto, es una instancia de cadena diferente, con una referencia diferente.
El objeto String se puede crear de las siguientes maneras:
String str = new String("abcd"); // Using the new operator
// str is assigned with "abcd" value at compile time.
String str="abcd"; // Using string literal
// str is assigned with "abcd" value at compile time.
String str="ab" + "cd"; // Using string constant expression.
// str is assigned with "abcd" value at compile time.
String str1 = "cd";
String str = "ab"+str1; // Using string expression.
// str is assigned with "abcd" value at run time only.
y Hashcode se calculará solo en tiempo de ejecución en función del contenido de los objetos String.
Es porque siguiendo el código
("Hel"+lo)) + " "
se traduce internamente a
new StringBuilder("Helo").append(new String(lo)).append(new String(" ")).toString()
Así que puedes ver que se crea una nueva instancia de String con la ayuda de diferentes instancias de String. Es por eso que obtienes falso ya que apuntan a diferentes ubicaciones de memoria en el montón
Esto se debe a que el comipler en esta instancia no es lo suficientemente inteligente para calcular que puede grabar en la misma cadena literal.
Hashcode siempre debe devolver el mismo valor para las cadenas que son equivalentes (llamar a .equals en él devuelve true), por lo que devolverá el mismo resultado.
La diferencia entre la línea número 3 y 4 es la siguiente.
• Las cadenas calculadas por expresiones constantes 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 nuevamente y, por lo tanto, son distintas.
La referencia anterior está tomada de la especificación de Java. Por favor, hágamelo saber si necesita más aclaraciones.
http://docs.oracle.com/javase/specs/jls/se7/html/jls-3.html#jls-3.10.5
Los literales de cadena se guardan en una memoria especial, si son exactamente iguales, se apuntan al mismo mapa de memoria. Si no crea una cadena literal, se creará un nuevo objeto para que no apunte a esa memoria, por lo que la referencia no será la misma.
El método interno () le dice a la máquina virtual que lo coloque en el mapa compartido de literales de cadena de la memoria, así que la próxima vez que haga ese literal, buscará allí y lo señalará.
System.identityHashCode()
sería devuelto por el método predeterminado hashCode()
, esto se implementa normalmente al convertir la dirección interna del objeto en un entero.
Las cadenas calculadas por concatenación en el tiempo de ejecución son de nueva creación y por lo tanto distintas
Aquí hay un enlace para leer: http://docs.oracle.com/javase/specs/jls/se7/html/jls-3.html#jls-3.10.5