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.

Captura de pantalla que muestra la fuente y que la salida es " false"

¿Qué está pasando aquí?

Author: Sam, 2018-06-21

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:

  1. 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")
  2. 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)
  3. 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.

 73
Author: Joachim Sauer,
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.

 36
Author: Oleksandr,
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.

 26
Author: Keveloper,
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

 5
Author: Chetan Jadhav CD,
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.

 4
Author: Randomness Slayer,
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

 2
Author: Alishan,
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.

 1
Author: Vamsi,
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  
 1
Author: Aadesk,
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)

 -4
Author: mmx,
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