Nessun risultato. Prova con un altro termine.
Guide
Notizie
Software
Tutorial

Tipi primitivi in Java: Arithmetic Promotion

Java: come funziona la promozione aritmetica del tipo, una conversione adottata dal compilatore Java in espressioni numeriche con tipi di dato differenti.
Java: come funziona la promozione aritmetica del tipo, una conversione adottata dal compilatore Java in espressioni numeriche con tipi di dato differenti.
Link copiato negli appunti

La promozione aritmetica del tipo è una conversione adottata dal compilatore Java nell'ambito di espressioni numeriche che coinvolgono tipi di dato differenti. Il compilatore necessita di effettuare delle adeguate conversioni sui tipi coinvolti in modo tale che l'espressione matematica abbia un tipo corretto per il risultato.

Compilatore e conversioni di tipo

Vediamo prima di tutto come il compilatore effettua le conversioni di tipo in casi molto semplici. In Java abbiamo a disposizione i seguenti tipi primitivi numerici: byte(8 bit), short(16 bit), int(32 bit), long(64 bit), float(32 bit) e double(64 bit).

Per comprendere come agisce il compilatore è fondamentale avere in mente le semplici regole di conversione implicita del tipo sulle tipologie numeriche appena elencate (Widening conversion):

  • una variabile di tipo byte può essere assegnata ad una di tipo short, int, long, float o double;
  • il valore contenuto nella variabile di tipo byte viene automaticamente convertito in un valore di tipo short, int, long, float o double;
  • una variabile di tipo short può essere assegnata ad una variabile di tipo int, long, float o double;
  • il valore contenuto nella variabile di tipo short viene automaticamente convertito in un valore di tipo int, long, float o double.

Applicando le stesse considerazioni e, seguendo l'ordine che abbiamo definito da short a double, deduciamo che un int può essere assegnato ad un long, float o double, un long ad un float o double ed un float soltanto ad un double.

Ovviamente ogni valore di tipo A può essere assegnato ad una variabile dello stesso tipo A. Queste conversioni di tipo sono automatiche perchè il valore di partenza appartiene ad un range numerico di cardinalità inferiore rispetto al range numerico del tipo di destinazione.

Questo aspetto è comprensibile notando il numero di bit utilizzati per la rappresentazione numerica di ciascun tipo. Sulla base di quanto appena detto mostriamo alcuni esempi in cui il compilatore effettua conversioni numeriche implicite:

byte valByte = 50;
short valShort = valByte;
int valInt = valShort;
long valLong = valInt;
float valFloat = valLong;
double valDouble = valFloat;

Tipi di dato e conversioni tra tipi

Cosa accade se proviamo ad assegnare un valore di una variabile di un tipo più grande ad una variabile di un tipo più piccolo? La risposta è un errore di compilazione. Il compilatore ci avverte dell'impossibilà di effettuare la conversione automatica in quanto il valore che si intende assegnare alla variabile di destinazione semplicemente potrebbe non essere contenuto nel suo range del tipo.

Pensiamo a un valore int che cerchiamo di assegnare ad una variabile di tipo byte. Il range del tipo int è -2.147.483.648,+2.147.483.647 mentre quello dei byte -128,+127, il compilatore considera il tipo della variabile e ci avverte dell'impossibilità di effettuare la conversione in quanto il range int non è contenuto nel range short. Il fatto che il compilatore consideri solo il tipo porta ad avere per l'istruzione

valByte = valInt;

un errore di compilazione anche se il valore contenuto nella variabile int è presente nel range dei valori di tipo byte.

Un aspetto interessante è un'eccezione a questo comportamento attuata dal compilatore nell'ambito di assegnazioni di valori numerici diretti ad una variabile (literals). In queste situazioni il compilatore rilassa le sue regole ed effettua una conversione del tipo se il valore, come nell'esempio precedente, è contenuto nel range del tipo di destinazione.

Questo è ciò che accade con la prima istruzione di assegnazione del valore 50 ad un tipo byte. Per comprendere questo aspetto occorre sapere che le costanti numeriche intere vengono automaticamente considerate come tipo int, mentre quelle in virgola mobile come double. Cosi l'istruzione

byte valByte = 50;

significa assegnare un int ad un byte. Il valore assegnato è un literal, il compilatore rilassa il suo comportamento osservando che il valore appartiene al range del tipo byte, ed effettua la conversione di tipo.

Esistono delle situazioni in cui possiamo forzare il compilatore chiedendo di convertire il valore contenuto in una variabile di range più grande in una di range più piccolo perchè sappiamo che il valore contenuto è rappresentabile dal tipo più piccolo (Narrowing conversion). Questa operazione si chiama casting esplicito. Un esempio:

valByte = (byte) valInt;

Occorre prestare attenzione ad un casting di questo tipo. Con riferimento all'istruzione precedente, se in valInt dovesse essere contenuto un valore non appartenente al range -128,+127 avremmo una perdita di informazioni con un risultato imprevedibile.

Vediamo adesso cosa accade quando differenti tipi sono coinvolti nell'ambito di una espressione aritmetica. Consideriamo il seguente frammento di codice:

short s = 2;
int i = 8;
float f = 12.8f;
double d = 12.5;
if(-s*i >= f/d)
 System.out.println(">=");
else
 System.out.println("

Il compilatore, prima di poter valutare l'espressione numerica contenuta nell'istruzione if, deve effettuare una serie di Widening conversion (per questo si parla di promozione del tipo) per ottenere il giusto tipo per il risultato dell'espressione.

Regole di promozione

Le regole che governano la promozione del tipo per le espressioni aritmetiche sono legate ai due tipi di operatori unario e binario. In caso di operatore binario (+,-,~) se l'operando numerico è un byte o short, viene convertito in un int, altrimenti nessuna conversione è applicata. Gli operatori unari ++,-- non sono soggetti a conversione.

Per gli operatori binari (+,-,*,&,%,...) si applicano le seguenti regole:

  • se uno degli operandi è un double l'altro operando è convertito ad un double;
  • se uno degli operandi è un float l'altro operando è convertito ad un float;
  • se uno degli operandi è un long, l'altro operando è convertito ad un long;
  • diversamente entrambi gli operandi sono convertiti a int.

Cosi in riferimento al codice precedente abbiamo i seguenti passi:

  • s è promossa ad int e negata;
  • s è un int ed è moltiplicata per i ottenendo un int, nessuna conversione necessaria;
  • f è promossa a double e quindi divisa per d che è un double, il risultato è un double;
  • abbiamo un int confrontato con un double attraverso l'operatore >= , l'int è convertito a double ed i valori sono confrontati restituendo un boolean.

Ti consigliamo anche