2010-10-02 18 views
13
int x=1; 
int y=2; 
x ^= y ^= x ^= y; 

Estoy esperando que los valores sean intercambiados. Pero da x = 0 y y = 1. cuando probé en lenguaje C da el resultado correcto.¿Por qué esta afirmación no funciona en java x^= y^= x^= y;

+4

Es un comportamiento indefinido en C, ya que está modificando tanto x como y dos veces en un punto de secuencia. –

+3

No lo uses. Usar una variable temporal adicional para intercambiar 2 es MUCHO más eficiente porque no tiene que hacer el cálculo. –

+1

@Imre: aceptaré su sugerencia. –

Respuesta

56

Su afirmación es más o menos equivalente a esta forma expandida:

x = x^(y = y^(x = x^y)); 

A diferencia de C, en Java se garantiza el operando izquierdo de un operador binario para ser evaluados antes de que el operador de la derecha. La evaluación se produce de la siguiente manera:

x = x^(y = y^(x = x^y)) 
x = 1^(y = 2^(x = 1^2)) 
x = 1^(y = 2^(x = 3)) 
x = 1^(y = 2^3)    // x is set to 3 
x = 1^(y = 1) 
x = 1^1      // y is set to 1 
x = 0       // x is set to 0 

Se podría invertir el orden de los argumentos a cada expresión XOR por lo que la asignación se realiza antes de la variable se evalúa de nuevo:

x = (y = (x = x^y)^y)^x 
x = (y = (x = 1^2)^y)^x 
x = (y = (x = 3)^y)^x 
x = (y = 3^y)^x    // x is set to 3 
x = (y = 3^2)^x 
x = (y = 1)^x 
x = 1^x      // y is set to 1 
x = 1^3 
x = 2       // x is set to 2 

Esta es una versión más compacta eso también funciona:

x = (y ^= x ^= y)^x; 

Pero esta es una manera realmente horrible de cambiar dos variables. Es una idea mucho mejor usar una variable temporal.

+11

+1 para "usar un temporal". –

+1

+1 Wow - buena respuesta. – duffymo

+0

¿Estás seguro? Pensé que una tarea era verdadera, ¿por qué si las instrucciones donde = se usaba en lugar de == siempre se ejecutaban? Eso significaría que su primera afirmación era la misma que x = x^verdadero^verdadero; – AaronM

13

Mark es completamente correcto acerca de cómo se evalúa en Java. La razón es JLS §15.7.2., Evaluar Operandos antes de la operación, y §15.7, que requiere la evaluación de izquierda a derecha:

Es equivalente (por §15.26.2, operadores de asignación compuestos) a:

x = x^(y = y^(x = (x^y))); 

Nosotros evaluamos izquierda a derecha , haciendo ambos operandos antes de la operación.

x = 1^(y = y^(x = (x^y))); // left of outer 
x = 1^(y = 2^(x = (x^y))); // left of middle 
x = 1^(y = 2^(x = (1^y))); // left of inner 
x = 1^(y = 2^(x = (1^2))); // right of inner 
x = 1^(y = 2^(x = 3)); // inner xor (right inner assign) 
x = 1^(y = 2^3); // inner assign (right middle xor) 
x = 1^(y = 1); // middle xor (right middle assign) 
x = 1^1; // middle assign (right outer xor) 
x = 0; // outer xor (right outer assign) 

Tenga en cuenta que es un comportamiento indefinido en C, porque está modificando la misma variable dos veces entre puntos de secuencia.

+1

+1 para enlaces a la especificación. –

Cuestiones relacionadas