java - paneles - ¿Por qué x==(x=y) no es lo mismo que(x=y)== x?
table swing java (14)
No estoy seguro de si hay un elemento en la especificación del lenguaje Java que dicta cargar el valor anterior de una variable ...
Ahi esta. La próxima vez que no tenga claro lo que dice la especificación, lea la especificación y luego haga la pregunta si no está claro.
... el lado derecho
(x = y)
que, según el orden implícito entre corchetes, debe calcularse primero.
Esa afirmación es falsa. Los paréntesis no implican un orden de evaluación . En Java, el orden de evaluación es de izquierda a derecha, independientemente de los paréntesis. Los paréntesis determinan dónde están los límites de la subexpresión, no el orden de evaluación.
¿Por qué la primera expresión se evalúa como falsa, pero la segunda se evalúa como verdadera?
La regla para el operador
==
es: evaluar el lado izquierdo para producir un valor, evaluar el lado derecho para producir un valor, comparar los valores, la comparación es el valor de la expresión.
En otras palabras, el significado de
expr1 == expr2
es siempre el mismo que si hubiera escrito
temp1 = expr1; temp2 = expr2;
temp1 = expr1; temp2 = expr2;
y luego evaluó
temp1 == temp2
.
La regla para el operador
=
con una variable local en el lado izquierdo es: evaluar el lado izquierdo para producir una variable, evaluar el lado derecho para producir un valor, realizar la asignación, el resultado es el valor que se asignó.
Así que ponlo juntos:
x == (x = y)
Tenemos un operador de comparación.
Evalúe el lado izquierdo para generar un valor; obtenemos el valor actual de
x
.
Evalúe el lado derecho: es una asignación, por lo que evaluamos el lado izquierdo para producir una variable, la variable
x
, evaluamos el lado derecho, el valor actual de
y
, se lo asignamos a
x
, y el resultado es el asignado valor.
Luego comparamos el valor original de
x
con el valor asignado.
Puedes hacer
(x = y) == x
como un ejercicio.
Una vez más, recuerde,
todas las reglas para evaluar el lado izquierdo suceden antes que todas las reglas para evaluar el lado derecho
.
Hubiera esperado que (x = y) se evaluara primero, y luego compararía x con sí mismo (3) y devolvería verdadero.
Su expectativa se basa en un conjunto de creencias incorrectas sobre las reglas de Java. Esperemos que ahora tenga las creencias correctas y en el futuro esperará cosas verdaderas.
Esta pregunta es diferente del "orden de evaluación de las subexpresiones en una expresión Java"
Esta afirmación es falsa. Esa pregunta es totalmente pertinente.
x definitivamente no es una ''subexpresión'' aquí.
Esta afirmación también es falsa. Es una subexpresión dos veces en cada ejemplo.
Debe cargarse para la comparación en lugar de ser "evaluado".
No tengo idea de qué significa.
Aparentemente todavía tienes muchas creencias falsas. Mi consejo es que lea la especificación hasta que sus creencias falsas sean reemplazadas por creencias verdaderas.
La pregunta es específica de Java y la expresión x == (x = y), a diferencia de construcciones poco probables e imprecisas comúnmente elaboradas para preguntas de entrevistas difíciles, provino de un proyecto real.
La procedencia de la expresión no es relevante para la pregunta. Las reglas para tales expresiones se describen claramente en la especificación; léelo
Se suponía que iba a ser un reemplazo de una línea para el lenguaje de comparación y reemplazo
Dado que el reemplazo de una línea causó una gran confusión en usted, el lector del código, sugeriría que fue una mala elección. Hacer el código más conciso pero más difícil de entender no es una victoria. Es poco probable que el código sea más rápido.
Por cierto, C # tiene comparaciones y reemplazos como un método de biblioteca, que puede reducirse a una instrucción de máquina. Creo que Java no tiene tal método, ya que no puede representarse en el sistema de tipo Java.
Considere el siguiente ejemplo:
class Quirky {
public static void main(String[] args) {
int x = 1;
int y = 3;
System.out.println(x == (x = y)); // false
x = 1; // reset
System.out.println((x = y) == x); // true
}
}
No estoy seguro de si hay un elemento en la Especificación del lenguaje Java que dicte cargar el valor anterior de una variable para compararla con el lado derecho (
x = y
) que, según el orden implícito entre corchetes, se debe calcular primero.
¿Por qué la primera expresión se evalúa como
false
, pero la segunda se evalúa como
true
?
Hubiera esperado que
(x = y)
se evaluara primero, y luego compararía
x
con sí mismo (
3
) y devolvería
true
.
Esta pregunta es diferente del
orden de evaluación de las subexpresiones en una expresión de Java
en que
x
definitivamente no es una ''subexpresión'' aquí.
Debe
cargarse
para la comparación en lugar de ser "evaluado".
La pregunta es específica de Java y la expresión
x == (x = y)
, a diferencia de construcciones poco probables e imprecisas comúnmente elaboradas para preguntas de entrevistas difíciles, provino de un proyecto real.
Se suponía que iba a ser un reemplazo de una línea para el lenguaje de comparación y reemplazo
int oldX = x;
x = y;
return oldX == y;
que, siendo incluso más simple que la instrucción x86 CMPXCHG, merecía una expresión más corta en Java.
el cual, por orden implícita entre paréntesis, debe ser calculado primero
No. Es un error común pensar que los paréntesis tienen algún efecto (general) en el orden de cálculo o evaluación. Solo coaccionan las partes de su expresión en un árbol particular, vinculando los operandos correctos a las operaciones correctas para el trabajo.
(Y, si no los usa, esta información proviene de la "precedencia" y la asociatividad de los operadores, algo que es el resultado de cómo se define el árbol de sintaxis del idioma. De hecho, esto es exactamente cómo funciona cuando use paréntesis, pero simplificamos y decimos que no estamos confiando en ninguna regla de precedencia en ese momento.)
Una vez hecho esto (es decir, una vez que su código ha sido analizado en un programa), esos operandos aún deben ser evaluados, y existen reglas separadas sobre cómo se hace esto: dichas reglas (como nos ha demostrado Andrew) establecen que el LHS de cada operación Se evalúa primero en Java.
Tenga en cuenta que este no es el caso en todos los idiomas;
por ejemplo, en C ++, a menos que esté utilizando un operador de cortocircuito como
&&
o
||
, el orden de evaluación de los operandos generalmente no se especifica y no debe confiar en él de ninguna manera.
Los maestros deben dejar de explicar la precedencia del operador usando frases confusas como "esto hace que la adición ocurra primero".
Dada una expresión
x * y + z
la explicación correcta sería "la precedencia del operador hace que la suma ocurra entre
x * y
y
z
, en lugar de entre
y
y
z
", sin ninguna mención de "orden".
== es un operador de igualdad de comparación y funciona de izquierda a derecha.
x == (x = y);
aquí el antiguo valor asignado de x se compara con el nuevo valor de asignación de x, (1 == 3) // falso
(x = y) == x;
Mientras que aquí, el nuevo valor de asignación de x se compara con el nuevo valor de retención de x asignado justo antes de la comparación, (3 == 3) // verdadero
Ahora considera esto
System.out.println((8 + (5 * 6)) * 9);
System.out.println(8 + (5 * 6) * 9);
System.out.println((8 + 5) * 6 * 9);
System.out.println((8 + (5) * 6) * 9);
System.out.println(8 + 5 * 6 * 9);
Salida:
342
278
702
342
278
Por lo tanto, los paréntesis desempeñan su papel principal en las expresiones aritméticas, pero no en las expresiones de comparación.
Básicamente, la primera declaración x tenía su valor 1 Por lo tanto, Java compara 1 == con la nueva variable x que no será la misma
En el segundo, dijiste que x = y, lo que significa que el valor de x cambió, por lo que cuando lo llames de nuevo, tendrá el mismo valor, por lo que es verdadero y x == x
Como dijo LouisWasserman, la expresión se evalúa de izquierda a derecha. Y a java no le importa lo que realmente hace "evaluar", solo le importa generar un valor (no volátil, final) para trabajar.
//the example values
x = 1;
y = 3;
Entonces, para calcular la primera salida de
System.out.println()
, se hace lo siguiente:
x == (x = y)
1 == (x = y)
1 == (x = 3) //assign 3 to x, returns 3
1 == 3
false
y para calcular el segundo:
(x = y) == x
(x = 3) == x //assign 3 to x, returns 3
3 == x
3 == 3
true
Tenga en cuenta que el segundo valor siempre se evaluará como verdadero, independientemente de los valores iniciales de
x
e
y
, porque está comparando efectivamente la asignación de un valor a la variable a la que está asignado, y
a = b
y
b
, evaluados en esa Orden, siempre será el mismo por definición.
Considera este otro ejemplo, quizás más simple:
int x = 1;
System.out.println(x == ++x); // false
x = 1; // reset
System.out.println(++x == x); // true
Aquí, el operador de
++x
en
++x
debe aplicarse
antes de que
se realice la comparación; al igual que
(x = y)
en su ejemplo, debe calcularse
antes de
la comparación.
Sin embargo, la
evaluación de expresiones todavía ocurre de izquierda a → derecha
, por lo que la primera comparación es en realidad
1 == 2
mientras que la segunda es
2 == 2
.
Lo mismo sucede en tu ejemplo.
El tipo de pregunta que hizo es una muy buena pregunta si desea escribir un compilador de Java o programas de prueba para verificar que un compilador de Java funciona correctamente. En Java, estas dos expresiones deben producir los resultados que viste. En C ++, por ejemplo, no tienen que hacerlo; por lo tanto, si alguien reutiliza partes de un compilador de C ++ en su compilador de Java, en teoría podría encontrar que el compilador no se comporta como debería.
Como desarrollador de software, escribir código que sea legible, comprensible y fácil de mantener, ambas versiones de su código se considerarán horribles. Para entender lo que hace el código, uno tiene que saber exactamente cómo se define el lenguaje Java. Alguien que escribe código Java y C ++ se estremecería al mirar el código. Si tiene que preguntar por qué una sola línea de código hace lo que hace, entonces debe evitar ese código. (Supongo y espero que los muchachos que respondieron a su pregunta "por qué" correctamente también eviten ese código).
En la primera prueba que estás comprobando hace 1 == 3.
En la segunda prueba su comprobación hace 3 == 3.
(x = y) asigna el valor y ese valor se prueba. En el ejemplo anterior, x = 1 primero, luego se asigna x 3. ¿1 == 3?
En este último, a x se le asigna 3, y obviamente sigue siendo 3. ¿3 == 3?
Es fácil que en la segunda comparación a la izquierda sea la asignación después de asignar y a x (a la izquierda), comparando 3 == 3. En el primer ejemplo, está comparando x = 1 con una nueva asignación x = 3. Parece que siempre se toman declaraciones de lectura del estado actual de izquierda a derecha de x.
La cosa aquí es el orden de prioridad de los operadores aritmáticos / operadores relacionales de los dos operadores
=
vs
==
el dominante es
==
(los operadores relacionales dominan) ya que precede a los operadores de asignación.
A pesar de la precedencia, el orden de evaluación es LTR (IZQUIERDA A DERECHA) la precedencia aparece en la imagen después de la orden de evaluación.
Por lo tanto, independientemente de cualquier restricción de evaluación es LTR.
Las expresiones se evalúan de izquierda a derecha. En este caso:
int x = 1;
int y = 3;
x == (x = y)) // false
x == t
- left x = 1
- let t = (x = y) => x = 3
- x == (x = y)
x == t
1 == 3 //false
(x = y) == x); // true
t == x
- left (x = y) => x = 3
t = 3
- (x = y) == x
- t == x
- 3 == 3 //true
No es lo mismo. El lado izquierdo siempre se evaluará antes que el lado derecho, y los paréntesis no especifican un orden de ejecución, sino una agrupación de comandos.
Con:
x == (x = y)
Básicamente estás haciendo lo mismo que:
x == y
Y x tendrá el valor de y después de la comparación.
Mientras que con
(x = y) == x
Básicamente estás haciendo lo mismo que:
x == x
Después de x tomó el valor de y. Y siempre volverá verdad .
Se relaciona con la precedencia del operador y cómo se evalúa a los operadores
Los paréntesis ''()'' tienen mayor prioridad y tienen asociatividad de izquierda a derecha. La igualdad ''=='' viene a continuación en esta pregunta y tiene asociatividad de izquierda a derecha. La asignación ''='' viene en último lugar y tiene asociatividad de derecha a izquierda.
Sistema de uso de la pila para evaluar la expresión. La expresión se evalúa de izquierda a derecha.
Ahora viene a la pregunta original:
int x = 1;
int y = 3;
System.out.println(x == (x = y)); // false
Primero se empujará x (1) para apilar. luego se evaluará el interior (x = y) y se empujará a la pila con el valor x (3). Ahora x (1) se comparará con x (3), por lo que el resultado es falso.
x = 1; // reset
System.out.println((x = y) == x); // true
Aquí, (x = y) se evaluará, ahora el valor de x se convertirá en 3 y x (3) se empujará para apilar. Ahora x (3) con un valor cambiado después de la igualdad será empujado para apilar. Ahora la expresión se evaluará y ambas serán iguales, por lo que el resultado es verdadero.
==
es un
operador de igualdad
binaria.
El operando de la izquierda de un operador binario parece estar completamente evaluado antes de que se evalúe cualquier parte del operando de la derecha .
Especificación de Java 11> Orden de evaluación> Evaluar el operando de la mano izquierda primero