Warum ist x == (x = y) nicht dasselbe wie (x = y) == x?

Betrachten Sie das folgende Beispiel:

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

Ich bin mir nicht sicher, ob es ein Element in der Java Language Specification, die vorschreibt laden des vorherigen Wert einer Variablen für den Vergleich mit der rechten Seite (x = y) die durch die Bestellung konkludent durch Klammern, sollte zuerst berechnet werden.

Warum wird der erste Ausdruck ausgewertet false, aber die zweite Auswertung true? Ich hätte erwartet (x = y) zuerst ausgewertet werden, und dann wäre es zu vergleichen x mit sich selbst (3) und zurück true.


Diese Frage unterscheidet sich von Reihenfolge der Auswertung der Teilausdrücke in einem Java-Ausdruck in diesem x ist definitiv kein 'Teilausdruck' hier. Es muss geladen für den Vergleich eher als 'bewertet'. Die Frage ist, Java-spezifischen und der Ausdruck x == (x = y) im Gegensatz zu weit hergeholt unpraktisch Konstrukte allgemein gestaltete für knifflige Fragen im interview, kam aus einem realen Projekt. Es war eigentlich eine one-line-Ersatz für die vergleichen-und-ersetzen-idiom

int oldX = x;
x = y;
return oldX == y;

werden, die, wenn auch einfacher als die x86-Instruktion CMPXCHG, verdient einen kürzeren Ausdruck in Java.

  • Der linken Seite wird immer ausgewertet, bevor der rechten Seite. Die Klammern nicht einen Unterschied machen, dass.
  • Der Begriff bewerten ist, meiner Meinung nach, nicht anwendbar, weil hier x muss nicht bewertet werden, es nur aus dem Speicher geladen.
  • Die Auswertung des Ausdrucks x = y ist sicherlich relevant, und verursacht der Nebeneffekt, dass x auf den Wert von y.
  • Sicher. Ich wusste, dass, und es war die Hauptidee, die mich führen zu quickReplaceAndCompare().
  • Tun Sie sich und Ihren Teamkollegen einen gefallen und don ' T mix Zustand-mutation in der gleichen Zeile wie Staatsexamen. Dabei drastisch reduziert, die Lesbarkeit des Codes. (Es gibt einige Fälle, in denen es absolut notwendig ist, wegen der Unteilbarkeit Anforderungen, funktioniert aber für diejenigen, die bereits vorhanden sind und deren Ziel es ist, sofort erkannt.)
  • Ein Beispiel für die frustration "shortcuts", wie dies verursachen kann, es hat mich den besseren Teil von einer minute, bis diese vollständig genug, um zu sehen, was diese tun. Ich weiß auch C++, und die Regeln sind anders in C++, als Sie hier in Java. In der Tat, in C++ ist dies zu undefiniertem Verhalten, so wirft es alle Arten geistiger roten Fahnen für mich, Bremsen Sie mich nach unten mehr, als Sie wahrscheinlich sollten. Ich wahrscheinlich Lesen Sie über replaceAndCompare 100 mal schneller als ich quickReplaceAndCompare.
  • Die Frage ist, warum Sie wollen, um code zu schreiben wie dieses.
  • Schreiben Sie niemals solchen code in der Produktion.
  • Ein weiterer Vorrang-Frage: Was sind die Regeln für die Evaluierung, um in Java?
  • Off: wenn es C ist, wäre es ein klarer Fall von UB, d.h. der compiler generiert möglicherweise etwas von ihm.
  • Jemand hat mir einmal erzählt, dass alle booleschen Ausdrücke haben drei mögliche Werte: True, False und "Bloody Stupid".
  • Tut Konstrukte, wie Sie in OP tatsächlich geben eine Garantie von Atomarität?
  • Der Schlüssel um deine Frage zu Ihrem falschen glauben, dass Klammern bedeuten Auswertung um. Das ist eine gemeinsame überzeugung, weil, wie wir gelehrt, Mathematik in der Grundschule und weil einige Anfänger-Programmier-Bücher noch get it wrong, aber es ist ein falscher glaube. Dies ist eine ziemlich häufige Frage. Könnten Sie davon profitieren, Lesen Sie meine Artikel über das Thema; Sie sind über C#, aber Sie gelten für Java: ericlippert.com/2008/05/23/precedence-vs-associativity-vs-order ericlippert.com/2009/08/10/precedence-vs-order-redux
  • Nein, ich beziehe mich auf Dinge wie dieser. Atomare Operationen sind explizit, also warum sind Sie sofort erkannt. Sorry für die nicht mehr klar.
  • Berücksichtigen Sie insbesondere so etwas wie x() * (y() + z()) Die Reihenfolge von Funktionsaufrufen ist nicht y, dann z, dann ist x, weil "die Klammern kommen zuerst". Die Klammern bestimmen den Teilausdruck Grenzen, nicht die Reihenfolge der Auswertung. Die * hat zwei Teilausdrücke: x() und (y() + z()). Auf der linken x(), passiert zuerst. Dann das richtige passiert: y() genannt wird, z() genannt wird, und Sie werden summiert. Dann die Multiplikation. Also die + geschieht, bevor die *, wie es kommen muss, aber die Operanden an den plus nicht passieren ersten.
  • Ich denke, dass ein Teil des Problems ist, dass Mathematik-Lehrer siehe Rangfolge der Regeln als der "order of operations", und das Wort "um" Reisen Menschen bis.
  • "x ist definitiv kein 'Teilausdruck' hier" - das ist Es wirklich. Warum denken Sie, dass der "laden" den Wert aus der variable wird nicht an Instanz von "evaluation"? Die Auswertung liefert einen Wert-nicht eine variable oder eine memory location.
  • Der original-poster ist, wie Sie merken, etwas verwirrt. Jedoch Ihre Aussage, dass die Auswertung liefert einen Wert, und nicht um eine variable, wird nicht unterstützt durch Beweise. Betrachten Sie zum Beispiel array()[index()] = value(); Die Semantik von Java, die wir als array(), dann index(), dann value(); all dies sind Werte. Aber wir müssen dann prüfen, ob die array-Referenz gültig ist und werfen, wenn es nicht ist, und dann prüfen, ob der index gültig ist, und werfen, wenn es nicht ist. Aber absolut der Teilausdruck Links von der Zuweisung nicht den Wert. Es ist eine variable.
  • Deine Aussage ist auch direkt im Widerspruch zu der von der Java-Spezifikation. Sprachen wie C unterscheiden zwischen "lvalues" und "rvalues"; ein "lvalue" ist der "Wert" erzeugt, durch die Auswertung der linken Seite einer Zuweisung. Dies wird zu Recht kritisiert als verwirrend, Java (und C#) vermeiden Sie dieses problem durch den Verzicht auf die Vorstellung, dass nur belegbare Dinge sind "Werte", und statt dessen nennen Sie das, was Sie sind: Variablen. Die Java-Spezifikation für die Zuordnung macht es sehr klar: "Zuerst der linke operand ausgewertet, um zu produzieren, eine variable..."
  • ist definitiv kein Teilausdruck "hier" - auf welcher Grundlage glaubst du das?
  • Weil der Ausdruck beinhaltet Betreiber(s).
  • Diese Aussage ist falsch; ein Ausdruck muss nicht mit jedem Betreiber. Wieder, Sie würde sehr gut tun zu Lesen der Spezifikation, denn Sie haben sehr viele falsche Vorstellungen. Befreien Sie sich von Ihnen!
  • Um zu sehen, von der spec (docs.oracle.com/javase/specs/jls/se11/html/jls-15.html), dass es Ausdrücke ohne Operatoren, können Sie die syntax der Expression terminal über mehrere Ebenen, durch PostFixExpression und ExpressionName. Oder schauen Sie auf MethodInvocation, deren ArgumentList besteht aus Komma-getrennten Ausdrücken. Wenn jeder Ausdruck erforderlich waren einzubeziehen, die die Operatoren, die Sie nicht bestehen könnte x als argument an eine Methode.
  • ein Ausdruck, der nicht notwendigerweise Betreiber(s). Hier, Sie werden sehen, dass Expression kann ein NameExpression (z.B. bezeichnet eine lokale variable), eine PrimaryExpression (z.B. bezogen auf eine primitive Literale), etc
  • Blick auf die Umsetzung der Map.computeIfAbsent() Schuld und sein Autor auch. Ja, ich weiß, dass Sie berechtigt sind, dies zu tun und ich bin nicht 🙂
  • Ich denke, wir reden bei der cross-Zwecke hier, da der Bezeichner "x" erscheint zweimal im Ausdruck, in der Diskussion, einmal auf der linken Seite der Gleichheits-operator, und eine auf der linken Seite eines Zuweisungs-operators. Ich nahm an, dass sich die Diskussion über die ehemalige, seit der OP spricht über "laden" den Wert. Den Teil der Spezifikation, die Sie zitieren, ist über den linken Operanden des zuweisungsoperators. Ich zugeben, dass ich Sprach unpräzis. Mein Punkt ist, dass die "Bewertung" der Links-Ausdruck nicht Ertrag eine Art lazy-Wert, können sich verschieben oder ändern, bevor das Vergleich Betrieb bewertet.
  • Meine interpretation des OP ' s mental model war: 1. bewerten == Operanden von Links nach rechts. 2. x braucht keine Bewertung, es ist nur "x" (Fehler). 3. bewerten (x = y) 4. Variable x wird aktualisiert, um den Wert von y, der Ausdruck hat den Wert von y, die 3. 5. bewerten == Betreiber. 6. Rufen Sie den aktuellen Wert der x und vergleichen Sie es mit 5. Wenn das der Fall ist, es ist nicht die Reihenfolge der Auswertung, die Sie bekommen haben, verwirrt. Es ist die Bedeutung von "Auswertung x".

InformationsquelleAutor John McClane | 2018-12-12
Schreibe einen Kommentar