¿Cómo puede una variable Java ser diferente de sí misma?

Me pregunto si esta pregunta se puede resolver en Java (soy nuevo en el lenguaje). Este es el código:

class Condition { // you can change in the main public static void main(String[] args) { int x = 0; if (x == x) { System.out.println("Ok"); } else { System.out.println("Not ok"); } } } 

Recibí la siguiente pregunta en mi laboratorio: ¿Cómo se puede omitir el primer caso (es decir, hacer que la condición x == x falsa) sin modificar la condición en sí?

Una forma simple es usar Float.NaN :

 float x = Float.NaN; // <-- if (x == x) { System.out.println("Ok"); } else { System.out.println("Not ok"); } 
 No está bien

Puedes hacer lo mismo con Double.NaN .


De JLS §15.21.1. Operadores de Igualdad Numérica == y != :

La prueba de igualdad de punto flotante se realiza de acuerdo con las reglas del estándar IEEE 754:

  • Si cualquiera de los operandos es NaN, entonces el resultado de == es false pero el resultado de != Es true .

    De hecho, la prueba x!=x es true si y solo si el valor de x es NaN.

...

 int x = 0; if (x == x) { System.out.println("Not ok"); } else { System.out.println("Ok"); } 

Por las especificaciones del lenguaje Java NaN no es igual a NaN .

Por lo tanto, cualquier línea que causara que x sea ​​igual a NaN podría causar esto, como

 double x=Math.sqrt(-1); 

De las especificaciones de lenguaje Java:

Los operadores de punto flotante no producen excepciones (§11). Una operación que se desborda produce un infinito con signo, una operación que subdesborda produce un valor desnormalizado o un cero firmado, y una operación que no tiene un resultado matemáticamente definido produce NaN. Todas las operaciones numéricas con NaN como operando producen NaN como resultado. Como ya se ha descrito, NaN no está ordenado, por lo que una operación de comparación numérica que involucre uno o dos NaNs devuelve falso y cualquier comparación! = Que involucre a NaN devuelve verdadero, incluyendo x! = X cuando x es NaN.

No estoy seguro de si esta es una opción, pero cambiar x de la variable local a un campo permitiría que otro subproceso cambie su valor entre el lado izquierdo y el derecho de lectura en el enunciado if .

Aquí hay una breve demostración:

 class Test { static int x = 0; public static void main(String[] args) throws Exception { Thread t = new Thread(new Change()); t.setDaemon(true); t.start(); while (true) { if (x == x) { System.out.println("Ok"); } else { System.out.println("Not ok"); break; } } } } class Change implements Runnable { public void run() { while (true) Test.x++; } } 

Salida:

 ⋮ Ok Ok Ok Ok Ok Ok Ok Ok Not ok 

La línea reemplazada podría leer.

 double x = Double.NaN; 

Esto causaría que se imprima el gotcha.

La especificación de lenguaje Java (JLS) dice:

Los operadores de punto flotante no producen excepciones (§11). Una operación que se desborda produce un infinito con signo, una operación que subdesborda produce un valor desnormalizado o un cero firmado, y una operación que no tiene un resultado matemáticamente definido produce NaN. Todas las operaciones numéricas con NaN como operando producen NaN como resultado. Como ya se ha descrito, NaN no está ordenado, por lo que una operación de comparación numérica que involucre uno o dos NaNs devuelve falso y cualquier comparación! = Que involucre a NaN devuelve verdadero, incluyendo x! = X cuando x es NaN.

Gotcha! obtener un Gotcha! de esto:

 volatile Object a = new Object(); class Flipper implements Runnable { Object b = new Object(); public void run() { while (true) { Object olda = a; a = b; a = olda; } } } public void test() { new Thread(new Flipper()).start(); boolean gotcha = false; while (!gotcha) { // I've added everything above this - I would therefore say still legal. if (a == a) { System.out.println("Not yet..."); } else { System.out.println("Gotcha!"); // Uncomment this line when testing or you'll never terminate. //gotcha = true; } } } 

Hay tantas soluciones:

 class A extends PrintStream { public A(PrintStream x) {super(x);} public void println(String x) {super.println("Not ok");} public static void main(String[] args) { System.setOut(new A(System.out)); int x = 0; if (x == x) { System.out.println("Ok"); } else { System.out.println("Not ok"); } } } 

Una solución fácil es:

 System.out.println("Gotcha!");if(false) if( a == a ){ System.out.println("Not yet..."); } else { System.out.println("Gotcha!"); } 

Pero no conozco todas las reglas de este enigma …

🙂 Sé que esto es una trampa, pero sin conocer todas las reglas, ¿es esta la solución más sencilla a la pregunta? 🙂

Cree su propio System clase en el mismo paquete con la Condition .
En este caso, su clase System ocultará la clase java.lang.System

 class Condition { static class System { static class out { static void println(String ignored) { java.lang.System.out.println("Not ok"); } } } public static void main (String[] args) throws java.lang.Exception { int x = 0; if (x == x) { System.out.println("Not ok"); } else { System.out.println("Ok"); } } } 

Ideone DEMO

Usando el mismo enfoque de salto / cambio de salida de otra respuesta:

 class Condition { public static void main(String[] args) { try { int x = 1 / 0; if (x == x) { System.out.println("Ok"); } else { System.out.println("Not ok"); } } catch (Exception e) { System.out.println("Not ok"); } } }