Wie kann sich eine Java-Variable von sich selbst unterscheiden?

106

Ich frage mich, ob diese Frage in Java gelöst werden kann (ich bin neu in der Sprache). Dies ist der Code:

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");
        }
    }
}

In meinem Labor erhielt ich die folgende Frage: Wie können Sie den ersten Fall überspringen (dh die x == xBedingung falsch machen), ohne die Bedingung selbst zu ändern?

Husam
quelle
12
Ich glaube, es sollte mehr Einschränkungen geben, sonst ist es zu offen.
Fermats kleiner Student
52
Ist es so einfach wie System.out.println("Gotcha!");anstelle des Kommentars? :)
stuXnet
6
Gut, dann ist double a = Double.NaN die kürzeste Antwort und mein "Hack ist nur ein Cheat;)
Christian Kuetbach
47
Dies ist eine nette Java-Trivia, aber ich hoffe, niemand wird in Betracht ziehen, daraus eine Interviewfrage zu machen. Menschen, die Kandidaten für eine Anstellung in Betracht ziehen, sollten ihr Bestes geben, um herauszufinden, ob der Kandidat die Programmierung versteht und nicht, wie viele Kleinigkeiten er angesammelt hat. Ich habe in 17 Jahren Programmierung in Java kaum Gleitkommazahlen verwendet, geschweige denn das NaN-Konstrukt, VIEL weniger zu wissen, wie es sich mit dem Operator == verhält ...
Arcy
8
@ user1158692 Frage der Meinung, ich hasse persönlich alle Programme , in denen die grundlegenden Operatoren außer Kraft gesetzt wurden und bin froh , dass jeder Code , den ich in Java empfangen hat nicht messed (I * außer Kraft gesetzt als das gesehen habe Vektor - Kreuzprodukt und das Skalarprodukt da beides sind Arten der Vektormultiplikation; ärgerlich! Während in Java das eine aufgerufen wird .cross()und das andere ist .dot()und es keine Verwirrung gibt. Auch die Tatsache, dass "den Operator == überschreiben und immer falsch zurückgeben" nicht vorkommen kann, scheint pro java
Richard Tingle

Antworten:

171

Ein einfacher Weg ist zu verwenden Float.NaN:

float x = Float.NaN;  // <--

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

Sie können das gleiche mit tun Double.NaN.


Aus JLS §15.21.1. Numerische Gleichheitsoperatoren ==und!= :

Gleitkomma-Gleichheitstests werden gemäß den Regeln des IEEE 754-Standards durchgeführt:

  • Wenn einer der Operanden NaN ist, ist das Ergebnis von ==is falseaber das Ergebnis von !=is true.

    Tatsächlich ist der Test x!=xist , truewenn und nur wenn der Wert xNaN ist.

...

arshajii
quelle
157
int x = 0;
if (x == x) {
    System.out.println("Not ok");
} else {
    System.out.println("Ok");
}
Jeroen Vannevel
quelle
63
Heh, das beantwortet die gestellte Frage völlig.
Dave Newton
5
@AswinMurugesh Richtig, aber wenn wir die Frage wie diese Antwort ganz wörtlich nehmen, können wir sie elseinsgesamt löschen . Dies würde technisch nicht gegen die Bestimmungen der Frage verstoßen.
Arshajii
67
In Anbetracht dessen, dass dies meine zweithöchste Antwort ist, bin ich mir nicht sicher, ob ich zu dem Schluss kommen soll, dass ich sehr lustig oder ein beschissener Programmierer bin.
Jeroen Vannevel
5
@JeroenVannevel Angesichts der Anforderungen denke ich, dass dies die am besten geeignete Antwort von KISS / YAGNI / ist;)
Izkata
12
@jddsantaella: offensichtlich wurde dies später bearbeitet. Die ursprüngliche Frage lautete "Wie kann ich" nicht in Ordnung "drucken?".
Jeroen Vannevel
147

Durch die Java-Sprachspezifikationen NaN ist nicht gleich NaN.

Daher würde jede Linie, die xgleich war, NaNdies verursachen, wie z

double x=Math.sqrt(-1);

Aus den Java-Sprachspezifikationen:

Gleitkommaoperatoren erzeugen keine Ausnahmen (§11). Eine Operation, die überläuft, erzeugt eine vorzeichenbehaftete Unendlichkeit, eine Operation, die unterläuft, erzeugt einen denormalisierten Wert oder eine vorzeichenbehaftete Null, und eine Operation, die kein mathematisch bestimmtes Ergebnis hat, erzeugt NaN. Alle numerischen Operationen mit NaN als Operanden erzeugen als Ergebnis NaN. Wie bereits beschrieben wurde, ist NaN ungeordnet, so dass eine numerische Vergleichsoperation mit einem oder zwei NaNs false zurückgibt und jeder! = Vergleich mit NaN true zurückgibt, einschließlich x! = X, wenn x NaN ist.

Richard Tingle
quelle
@ sᴜʀᴇsʜᴀᴛᴛᴀ Ein fairer Punkt, ich war so beschäftigt, die besagte "Codierungskonvention" zu finden, dass ich vergaß, die Frage tatsächlich zu beantworten
Richard Tingle
Dies gilt nur, wenn a als Object oder double deklariert ist.
Christian Kuetbach
1
@ChristianKuetbach Richtig, da keine gegenteiligen Informationen vorliegen, habe ich angenommen, dass die auskommentierte Zeile alles sein kann
Richard Tingle
2
Sogar meine betrogene Antwort ist richtig und erfüllt die Regeln. Ich habe nur vor der if-Anweisung bearbeitet und nur "Gotcha!" Wird ausgedruckt. Ich bin sicher, dass diese Antwort nicht die Antwort des Erstellers dieses Rätsels ist. Aber das Rätsel ist nicht genau definiert (wie die meisten Softwareprojekte ).
Christian Kuetbach
73

Ich bin mir nicht sicher, ob dies eine Option ist, aber der Wechsel xvon einer lokalen Variablen zu einem Feld würde es einem anderen Thread ermöglichen, seinen Wert zwischen dem Lesen der linken und rechten Seite in der ifAnweisung zu ändern .

Hier ist eine kurze Demo:

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++;
    }
}

Ausgabe:

⋮
Ok
Ok
Ok
Ok
Ok
Ok
Ok
Ok
Not ok
Pshemo
quelle
8
Haha +1 für Mühe, aber Mann ... es gibt keine Möglichkeit, dass sich jemand in meinem Java-Labor so etwas ausgedacht hätte (einschließlich Instruktor).
William Gaul
28
@ WilliamGaul Wirklich? Ich denke immer, dass es eines der grundlegenden Beispiele ist, die mögliche Probleme mit Multithreading aufzeigen und warum Leute, die denken, dass dieses Thema einfach ist, niemals für irgendetwas verantwortlich sein sollten :)
Pshemo
4
Ich habe nicht einmal über dieses Problem nachgedacht, bis ich Ihre Antwort gelesen habe. Vielen Dank, dass Sie dies zu meinem mentalen Toolkit hinzugefügt haben :)
Behe
56

Die ersetzte Zeile konnte lesen.

double x = Double.NaN;

Dies würde dazu führen, dass das Gotcha gedruckt wird.

Java Language Specification (JLS) sagt:

Gleitkommaoperatoren erzeugen keine Ausnahmen (§11). Eine Operation, die überläuft, erzeugt eine vorzeichenbehaftete Unendlichkeit, eine Operation, die unterläuft, erzeugt einen denormalisierten Wert oder eine vorzeichenbehaftete Null, und eine Operation, die kein mathematisch bestimmtes Ergebnis hat, erzeugt NaN. Alle numerischen Operationen mit NaN als Operanden erzeugen als Ergebnis NaN. Wie bereits beschrieben wurde, ist NaN ungeordnet, so dass eine numerische Vergleichsoperation mit einem oder zwei NaNs false zurückgibt und jeder! = Vergleich mit NaN true zurückgibt, einschließlich x! = X, wenn x NaN ist.

Mex
quelle
Oder führen Sie zu einem Kompilierungsfehler, wenn a als String a = "Nope" deklariert ist; Deshalb habe ich nach dem Typ 'a' gefragt
Christian Kuetbach
Der obige Code gibt keine Informationen über Typen, daher habe ich angenommen, dass a nicht bereits definiert ist.
Mex
Ich denke, dass Ihre Antwort die Antwort ist, die der Rätselschöpfer im Kopf hatte. Aber die Regeln waren nicht klar. Es wurden nur zwei Regeln angegeben: 1. Nur in die Zeile mit dem Kommentar einfügen und 2. Nur eine "Gotcha!"
Ausdrucken
Der Rätselautor hätte es immer gültig machen können, indem er den Code in {}
Mex
30

Ich habe es geschafft, eine Gotcha!davon zu bekommen :

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;
    }
  }
}
OldCurmudgeon
quelle
1
Dies ändert mehr als nur den Kommentar, wie es die Frage verlangt.
Mex
Ich habe so etwas versucht, aber ich denke, es ist garantiert, dass es immer das gleiche Ergebnis liefert, nicht wahr?
AndreDurao
4
@Mex - Es funktioniert zwar, aber es bewahrt genug vom Original, um einen weiteren wichtigen Punkt zu demonstrieren, der manchmal, a != aweil es von einem anderen Thread geändert wurde. Ich vermute, dass dies in einem Interview Punkte gewinnen würde.
OldCurmudgeon
Das ist eigentlich ziemlich klug, ich gehe davon aus, dass dies durch "Hoffen" funktioniert, adas durch den ersten Thread zwischen dem ersten und zweiten Zugriff zum Vergleich geändert wird
Richard Tingle
4
Re deine Zweifler; Es ist erwähnenswert, dass alles, was Sie über der Schlüsselaussage ifgeschrieben haben, bei Bedarf in einer einzigen schrecklichen Zeile geschrieben werden kann
Richard Tingle
25

Es gibt so viele Lösungen:

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");
        }
    }
}
Johannes Kuhn
quelle
1
Wenn mir nichts fehlt, super.printlnsollte das "Nicht in Ordnung" sein, oder?
Izkata
@Izkata Ja, ich habe nicht erneut überprüft, wie die gewünschte Ausgabe aussehen soll.
Johannes Kuhn
2
Absolut brilliant!
Dariusz
25

Eine einfache Lösung ist:

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

Aber ich kenne nicht alle Regeln für dieses Rätsel ...

:) Ich weiß, dass dies ein Betrug ist, aber ohne alle Regeln zu kennen, ist dies die einfachste Lösung für die Frage :)

Christian Kuetbach
quelle
1
Kann in einer Zeile geschrieben werden;)
Christian Kuetbach
6
@ChristianKuetbach Wie alle Programme
Richard Tingle
2
@ChristianKuetbach Um fair zu sein, sollte der Compiler sofort alle Dateien auf Ihrem Computer löschen, wenn Sie versucht haben, tatsächlich so zu programmieren
Richard Tingle
1
Warum es so schwierig machen? if (System.out.println("Gotcha") && false)
Alexis
3
Fehler: 'void' Typ hier nicht erlaubt wenn (System.out.println ("Gotcha") && false) Ihr Code wird nicht kompiliert ...
Christian Kuetbach
11

Erstellen Sie Ihre eigene Klasse Systemim selben Paket mit Condition.
In diesem Fall wird Sie Systemwird Klasse verstecken java.lang.SystemKlasse

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

Ilya
quelle
9

Verwenden des gleichen Ansatzes zum Überspringen / Ändern der Ausgabe aus anderen Antworten:

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");
        }
    }
}
Higuaro
quelle