En Java, entiendo que la asignación evalúa el valor del operando correcto, por lo que declaraciones como x == (y = x)
evaluar atrue
.
Este código, sin embargo, genera false
.
public static void main(String[]args){
String x = "hello";
String y = "goodbye";
System.out.println(x.equals(x = y));
}
¿Por qué es esto? Según tengo entendido, primero evalúa (x = y)
, que asigna x
el valor de y
y luego devuelve el valor de y
. Luego x.equals(y)
se evalúa, que debería ser true
desde x
y y
debería compartir las mismas referencias ahora, pero en cambio, obtengo false
.
¿Que está sucediendo aquí?
x.equals( y = x )
x
yy
?x = y
se ejecuta en el lado derecho antes de lax
se evalúa en el lado de la mano izquierda?x == (y = x)
evalúa como verdadero. El comportamiento de lo que sugieres entonces sería obvio ...Respuestas:
En primer lugar: esa es una pregunta interesante, pero nunca debería aparecer en "código real", ya que asignar a la variable que llamas en la misma línea es confuso incluso si sabes cómo funciona.
Lo que sucede aquí son estos 3 pasos:
x
, esto dará como resultado una referencia a la cadena "hola")x = y
, evaluar , que cambiaráx
para apuntar a la Cadena "adiós" y también devolverá una referencia a esa Cadena)equals
en el resultado de # 1 usando el resultado de # 2 como parámetro (que serán referencias a las cadenas "hola" y "adiós" respectivamente).Al observar el código de bytes producido para ese método, queda claro (suponiendo que domine el código de bytes de Java):
0: ldc #2 // String hello 2: astore_1 3: ldc #3 // String goodbye 5: astore_2 6: getstatic #4 // Field java/lang/System.out:Ljava/io/PrintStream; 9: aload_1 10: aload_2 11: dup 12: astore_1 13: invokevirtual #5 // Method java/lang/String.equals:(Ljava/lang/Object;)Z 16: invokevirtual #6 // Method java/io/PrintStream.println:(Z)V 19: return
La línea # 9 es el paso 1 anterior (es decir, evalúa
x
y recuerda el valor).La línea # 10-12 es el paso 2. La carga
y
, la duplica (una vez para asignar, una vez para el valor de retorno de la expresión de asignación) y la asigna ax
.La línea # 13 invoca
equals
el resultado calculado en la línea # 9 y el resultado de las líneas # 10-12.fuente
x.equals(x = y)
=>"hello".equals(x = y)
=>"hello".equals(x = "goodbye")
=>"hello".equals("goodbye")
=>false
..
tiene mayor precedencia que=
.¡Buena pregunta! Y el JLS tiene la respuesta ...
§15.12.4.1 (Ejemplo 15.12.4.1-2). Orden de evaluación durante la invocación del método:
Entonces, en:
String x = "hello"; String y = "goodbye"; System.out.println(x.equals(x = y));
la ocurrencia de
x
before.equals
se evalúa primero, antes de la expresión de argumentox = y
.Por lo tanto, una referencia a la cadena
hello
se recuerda como la referencia de destino antes de que la variable localx
se cambie para hacer referencia a la cadenagoodbye
. Como resultado, elequals
método se invoca para el objeto de destinohello
con argumentogoodbye
, por lo que el resultado de la invocación esfalse
.fuente
Es importante recordar que
String
en java es un objeto y, por lo tanto, una referencia. Cuando usted llamaEstá comprobando si el valor en la ubicación a la que se hace referencia actualmente
x
es igual a lo que está pasando. En el interior, está cambiando el valor quex
hace referencia , pero todavía está llamandoequals
con la referencia original (la referencia a "hola"). Entonces, ahora mismo su código se está comparando para ver si "hola" es igual a "adiós", lo cual claramente no es así. Después de este punto, si lo usax
nuevamente, resultará en una referencia al mismo valor que y.fuente
"hello".equals((x = y))
debería volvertrue
?x=y
entre paréntesis significa que la expresión(x=y)
es ahoragoodbye
, mientras que la x exteriorx.equals
tiene el valorhello
fuente
Reimus dio la respuesta correcta, pero me gustaría dar más detalles.
En Java (y la mayoría de los lenguajes) la convención es variable va a la izquierda, asignación a la derecha.
Vamos a analizarlo:
String x = "hello"; //x <- "hello" String y = "goodbye"; //y <- "goodbye";
Para fines de depuración y legibilidad del código, siempre es una buena práctica dividir las líneas para que solo hagan una cosa.
System.out.println(x.equals(x = y)); //Compound statement
Aquí,
x.equals(...)
se llama a la referencia original ax, o "hola", se actualiza para la segunda referencia.Escribiría esto como (y esto le dará la respuesta esperada):
x = y; // x <- y = "goodbye" boolean xEqualsX = x.equals(x); // xEqualsX <- true System.out.println(xEqualsX); // "true"
Ahora bien, esto parece obvio que debería comportarse de esta manera, pero también es muy fácil ver exactamente lo que está sucediendo en cada línea, que es algo por lo que debes esforzarte.
fuente
System.out.println("Bytes: "+1024*k);
se escribiera como tres declaraciones?He intentado su pregunta en eclipse, ambas expresiones son correctas. 1) x == (y = x) evaluar como verdadero, es cierto porque el valor de x se asigna a y, que es 'hola', luego xey comparan serán iguales, por lo que el resultado será verdadero
2) x.equal (x = y) es falso porque el valor de y se asigna a x que es adiós, entonces xyx comparan su valor será diferente, por lo que el resultado será falso
fuente
Veo la pregunta en términos simples como
"hello".equals("goodbye")
. Entonces devuelve falso.fuente
En Java String es una clase.
String x = "hello"; String y = "goodbye";
es una cadena de dos diferentes que se refieren a dos valores diferentes que no son iguales y si compara
System.out.println(x.equals(x = y)); //this compare value (hello and goodbye) return true System.out.println(x == (y = x)); // this compare reference of an object (x and y) return false
fuente
System.out.println(x.equals(x = y));
devuelve falso, al contrario de lo que afirma su respuesta.Está viendo si x.equals (asignar xay, devuelve verdadero siempre) así que básicamente x.equals (verdadero)
fuente