Ejecución del operador de asignación Java
En Java, entiendo que la asignación evalúa al valor del operando correcto, por lo que las sentencias como x == (y = x)
evalúan a true
.
Este código, sin embargo, produce false
.
public static void main(String[]args){
String x = "hello";
String y = "goodbye";
System.out.println(x.equals(x = y));
}
¿Por qué es esto? En mi opinión, primero evalúa (x = y)
, que asigna x
el valor de y
, y luego devuelve el valor de y
. Luego se evalúa x.equals(y)
, que debería ser true
ya que x
y y
deberían compartir las mismas referencias ahora, pero en cambio, obtengo false
.
¿Qué está pasando aquí?
9 answers
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:
- averigüe en qué objeto llamar al método (es decir, evalúe el primer
x
, esto resultará en una referencia a la cadena "hello") - averiguar los parámetros (es decir, evaluar
x = y
, que cambiaráx
para apuntar a la String "goodbye" y también devuelve una referencia a esa cadena) - llame al método
equals
en el resultado de #1 usando el resultado de #2 como parámetro (que serán referencias a las cadenas "hello" y "goodbye" respectivamente).
Mirando el código de bytes producido para ese método lo deja claro (suponiendo que usted es fluido en Java bytecode):
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. Se carga y
, lo duplica (una vez para asignar, una vez para el valor devuelto de la expresión de asignación) y lo asigna a x
.
La línea #13 invoca equals
en el resultado calculado en la Línea #9 y el resultado de las Líneas #10-12.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-06-21 13:53:06
¡Buena pregunta! Y la 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:
Como parte de una invocación de método de instancia, hay una expresión que denota el objeto a invocar. Esta expresión parece ser plenamente evaluado antes de cualquier parte de cualquier expresión de argumento al método se evalúa la invocación.
Así que, en:
String x = "hello";
String y = "goodbye";
System.out.println(x.equals(x = y));
La aparición de x
antes .equals
se evalúa primero, antes del argumento expression x = y
.
Por lo tanto, una referencia a la cadena hello
se recuerda como la referencia de destino antes de que la variable local x
se cambie para referirse a la cadena goodbye
. Como resultado, el método equals
se invoca para el objeto de destino hello
con el argumento goodbye
, por lo que el resultado de la invocación es false
.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-06-21 20:06:19
Es importante recordar que un String
en java es un objeto, y por lo tanto una referencia. Cuando llamas
x.equals(...)
Está comprobando si el valor en la ubicación actualmente referenciada por x
es igual a lo que está pasando. Dentro, está cambiando el valor que x
es haciendo referencia a, pero todavía está llamando a equals
con la referencia original (la referencia a "hola"). Por lo tanto, en este momento su código está comparando para ver si "hola" es igual a "adiós", que claramente no lo es. Después de este punto, si utiliza x
de nuevo, resultará en una referencia al mismo valor que y.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-06-21 13:47:44
x=y
en el paréntesis significa que la expresión (x=y)
es ahora goodbye
, mientras que la x externa en x.equals
contiene el valor hello
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-06-21 13:46:49
Reimus dio la respuesta correcta, pero me gustaría explicar.
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 desglosarlo:
String x = "hello";
//x <- "hello"
String y = "goodbye";
//y <- "goodbye";
Para fines de depuración, así como para la 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 en la referencia original a x, o "hola", se actualiza para la segunda referencia.
I escribiría esto como (y esto le dará su 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 debe 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.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-06-21 13:57:03
He intentado su pregunta en eclipse sus dos expresiones son correctas. 1) x == (y = x) evaluar a verdadero es verdad porque el valor de x asigna a y que es 'hola' entonces x e y comparan ellos el mismo resultado será verdadero
2) x. igual (x = y) es falso debido a que el valor de y asignar a x que es adiós entonces x y x comparar su valor será diferente por lo que el resultado será false
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-06-27 20:48:11
Veo la pregunta en términos laicos como "hello".equals("goodbye")
. Así que devuelve false.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-06-22 19:05:09
En java String es una clase.
String x = "hello";
String y = "goodbye";
Es una cadena diferente de dos que se refieren a dos valores diferentes que no son iguales y si comparas
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
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-06-28 06:17:33
Está viendo si x. equals (asignar x a y, devuelve true siempre) así que básicamente x. es igual a (verdadero)
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-06-22 19:14:12