Unterschiedliches Verhalten für eine möglichen Verlust an Präzision
-
01-10-2019 - |
Frage
In Java, wenn Sie das tun
int b = 0;
b = b + 1.0;
Sie erhalten einen möglichen Verlust an Präzision Fehler. Aber warum ist es, dass, wenn Sie tun
int b = 0;
b += 1.0;
Es gibt keinen Fehler?
Lösung
Das ist, weil b += 1.0;
äquivalent zu b = (int) ((b) + (1.0));
. Die Verengung primitive Umwandlung (JLS 5.1.3) wird in der Verbindung Zuweisungsoperation versteckt.
JLS 15.26. 2 Verbindung Zuweisungsoperator (JLS Dritte Ausgabe):
Eine Verbindung Zuweisungsausdruck von der Form E1 op = E2 entspricht E1 = (T) ((E1) op (E2)) , wobei T ist die Art von E1 , mit der Ausnahme, dass E1 wird nur einmal ausgewertet.
Zum Beispiel der folgende Code korrekt ist:
short x = 3; x += 4.6;
und Ergebnisse in
x
den Wert7
hat, weil es entspricht:short x = 3; x = (short)(x + 4.6);
Dies erklärt auch, warum die folgenden Code kompiliert:
byte b = 1;
int x = 5;
b += x; // compiles fine!
Aber das bedeutet nicht:
byte b = 1;
int x = 5;
b = b + x; // DOESN'T COMPILE!
Sie müssen in diesem Fall explizit Stimmen:
byte b = 1;
int x = 5;
b = (byte) (b + x); // now it compiles fine!
Es ist erwähnenswert, dass die implizite Umwandlung in Verbindung Zuweisungen ist das Thema Puzzle 9: Tweedledum aus dem wunderbaren Buch Java Puzzlers . Hier sind einige Auszüge aus dem Buch (leicht zur Kürze bearbeitet):
Viele Programmierer denken, dass
.x += i;
ist einfach eine Abkürzung fürx = x + i;
. Das ist nicht ganz richtig: wenn der Typ des Ergebnisses ist breiter als die der variablen, führt die Verbindung Zuweisungsoperator einer stille Verengung primitive UmwandlungUm unangenehme Überraschungen zu vermeiden, verwenden Sie keine Verbindung Zuweisungsoperator auf Variablen vom Typ
byte
,short
oderchar
. Bei der Verwendung von Verbindung Zuweisungsoperatoren auf Variablen vom Typint
, sicherzustellen, dass der Ausdruck auf der rechten Seite ist nicht vom Typlong
,float
oderdouble
. Bei der Verwendung von Verbindung Zuweisungsoperatoren auf Variablen vom Typfloat
, sicherzustellen, dass der Ausdruck auf der rechten Seite ist nicht vom Typdouble
. Diese Regeln sind ausreichend, um die Compiler zu erzeugen gefährliche Verengung Abgüsse zu verhindern.Für Sprachdesigner, ist es wahrscheinlich ein Fehler für Verbindung Zuweisungsoperator zu unsichtbaren Abgüsse zu erzeugen; Verbindung Zuweisungen, bei denen die Variablen einen engeren Typen als das Ergebnis der Berechnung haben, sollten wahrscheinlich illegal sein.
Der letzte Absatz ist bemerkenswert: C # viel strenger in dieser Hinsicht ist (siehe C # Language Specification 7.13.2 Verbindung Zuordnung ).