Warum würde ich + = l kompilieren, wo ich int und l lang ist?

8

Ich entdeckte Java's + =, - =, * =, / = zusammengesetzte Zuweisungsoperatoren (gute Frage :)) , aber es hatte einen Teil, den ich nicht ganz verstehe. Entlehnung von dieser Frage:

%Vor%      

Dann wird i = i + l; nicht kompiliert, aber i += l; wird kompiliert.

Die akzeptierte Antwort auf die verknüpfte Frage besagt:

  

Ein zusammengesetzter Zuordnungsausdruck der Form E1 op = E2 ist äquivalent zu E1 = (T) ((E1) op (E2)), wobei T der Typ von E1 ist, außer dass E1 nur einmal bewertet wird. p>

was bedeutet, dass i += l; dasselbe ist wie i = (int)((i) + (l)); mit der Ausnahme, dass i nur einmal ausgewertet wird.

A long kann sein (IIRC ist sogar garantiert) länger als ein int und kann daher einen viel größeren Wertebereich enthalten.

Da diese Situation sehr leicht zu Datenverlusten führen kann, weil während der Ausführung der Anweisung (entweder r-value-Ausdruckauswertung oder -zuweisung) die Konvertierung zu einem bestimmten Zeitpunkt eingeschränkt wird, ist i += l; kein Kompilierungsfehler oder zumindest Warnung?

    
Michael Kjörling 03.01.2012, 14:03
quelle

3 Antworten

8
  

Angesichts der Tatsache, dass diese Situation sehr leicht zu Datenverlusten führen kann, weil während der Ausführung der Anweisung (entweder r-value-Ausdruckauswertung oder -zuweisung) an einer bestimmten Stelle die Konvertierung eingeschränkt wird, ist i + = l; kein Kompilierfehler oder zumindest eine Warnung?

Es sollte wahrscheinlich, wie Sie sagten, entweder ein Kompilierungsfehler oder zumindest eine Warnung sein. Die meisten Bücher und Tutorials, die mir bekannt sind, führen x += y; als Kurzschrift für x = x + y; ein. Ich weiß ehrlich gesagt nichts von dem, was die im Abschnitt 15.26.2 Zusammengesetzte Zuweisungsoperatoren der JLS mit Ausnahme einer.

In Kapitel 2 (Puzzle 9) von Java Puzzlers: Fallen, Fallstricke und Eckfälle den Autoren ( Joshua Bloch und Neal Gafter) bitten Sie, Deklarationen für x und i anzugeben, so dass dies eine rechtliche Aussage ist:

%Vor%

und das ist nicht:

%Vor%

Es gibt viele Lösungen, einschließlich der ersten zwei Codezeilen, die Sie in Ihrer Frage gepostet haben. Die Autoren warnen davor, zusammengesetzte Zuweisungsoperatoren für Variablen vom Typ byte , short und char zu verwenden und empfehlen, dass bei Verwendung dieser Operatoren für Variablen vom Typ int sichergestellt werden sollte, dass der RHS-Ausdruck kein a ist long , float oder double .

Sie schließen mit der folgenden Beobachtung (Hervorhebung von mir):

  

Zusammenfassend generieren zusammengesetzte Zuweisungsoperatoren automatisch einen Cast. Wenn der Typ des Ergebnisses der Berechnung breiter ist als der der Variablen, ist der generierte Cast ein gefährlicher Narrowcast. Solche Modelle können die Präzision oder Größe stillschweigend verwerfen. Für Sprachdesigner ist es wahrscheinlich ein Fehler, wenn zusammengesetzte Zuweisungsoperatoren unsichtbare Umwandlungen erzeugen; Verbundzuordnungen, bei denen die Variable einen schmaleren Typ hat als das Ergebnis der Berechnung, sollten wahrscheinlich illegal sein.

    
Bill the Lizard 16.02.2012, 00:17
quelle
14

Grundsätzlich, weil i += l so kompiliert wird, als wäre es i = (int) (i + l) geschrieben. Es gibt ähnliche "Überraschungen" beim Hinzufügen von int -Werten zu byte und char Variablen - der Zuweisungsoperator funktioniert, während der einfache Additionsoperator nicht funktioniert.

    
Ernest Friedman-Hill 03.01.2012 14:06
quelle
1

Der Grund dafür ist, dass Sie Folgendes tun können:

%Vor%

Wenn + = zu b = b + 1 erweitert wurde, dann würde der Ausdruck keine Überprüfung geben, weil der Ausdruck "b + 1" vom Typ int ist. Alle Integralausdrücke in Java sind mindestens der Int-Typ, selbst wenn Sie zwei Bytes zusammenfügen.

%Vor%     
benmmurphy 16.02.2012 09:29
quelle