Variando il comportamento per la possibile perdita di precisione
-
01-10-2019 - |
Domanda
In Java, quando si esegue
int b = 0;
b = b + 1.0;
Si ottiene una possibile perdita di errore di precisione. Ma perché è che se si fa
int b = 0;
b += 1.0;
Non è un qualsiasi errore?
Soluzione
Questo perché b += 1.0;
equivale a b = (int) ((b) + (1.0));
. I restringimento di conversione primitiva (JLS 5.1.3) è nascosto nel funzionamento assegnazione composta.
JLS 15.26. 2 Operatori di assegnazione composti (JLS Terza edizione):
Un'espressione assegnazione composta di modulo E1 op = E2 è equivalente a E1 = (T) ((E1) op (E2)) , dove T è il tipo di E1 , tranne che E1 viene valutata solo una volta.
Ad esempio, il seguente codice è corretto:
short x = 3; x += 4.6;
e comporta
x
avente7
valore perché equivale a:short x = 3; x = (short)(x + 4.6);
Questo spiega anche perché le compilazioni seguente codice:
byte b = 1;
int x = 5;
b += x; // compiles fine!
Ma questo non:
byte b = 1;
int x = 5;
b = b + x; // DOESN'T COMPILE!
È necessario lanciare in modo esplicito in questo caso:
byte b = 1;
int x = 5;
b = (byte) (b + x); // now it compiles fine!
vale la pena di notare che il cast implicito nelle assegnazioni compound è oggetto di Puzzle 9: Panco Pinco dal bellissimo libro Java Puzzlers . Ecco alcuni estratto dal libro (leggermente modificato per brevità):
Molti programmatori pensano che
.x += i;
è semplicemente una scorciatoia perx = x + i;
. Questo non è del tutto vero: se il tipo del risultato è più ampio di quello della variabile, l'assegnazione composto operatore esegue un silenzioso restringimento di conversione primitivaPer evitare spiacevoli sorprese, non utilizzare operatori di assegnazione composti da variabili di tipo
byte
,short
ochar
. Quando si utilizzano operatori di assegnazione composti sulle variabili di tipoint
, assicurarsi che l'espressione sul lato destro non è di tipolong
,float
odouble
. Quando si utilizzano operatori di assegnazione composti sulle variabili di tipofloat
, assicurarsi che l'espressione sul lato destro non è di tipodouble
. Queste regole sono sufficienti per impedire al compilatore di generare getti restringimento pericolosi.Per i progettisti lingua, è probabilmente un errore per gli operatori di assegnazione composti per generare calchi invisibili; assegnamenti composti in cui la variabile ha un tipo più stretto del risultato del calcolo deve probabilmente essere illegale.
L'ultimo paragrafo è degno di nota: C # è molto più severa in proposito (vedi C # Specifiche del linguaggio 7.13.2 Compound assegnazione ).