Due famiglie: primitivi e riferimenti
Ogni valore in Java ha un tipo, e quel tipo appartiene a una di due famiglie. I tipi primitivi contengono direttamente un valore grezzo: un numero, un singolo carattere o un vero/falso. I tipi riferimento contengono un riferimento (un puntatore) a un oggetto che si trova altrove in memoria: String, gli array e ogni classe definita da te o dalle librerie.
La distinzione conta perché i primitivi sono leggeri e vengono copiati per valore, mentre le variabili riferimento puntano a oggetti condivisi. Parti dagli otto primitivi: sono le fondamenta su cui è costruito tutto il resto.
Gli otto tipi primitivi
Java ha esattamente otto tipi primitivi predefiniti. Sei sono numeri, uno è un carattere e uno è un booleano:
Alcune cose da notare subito: i trattini bassi in 2_000_000 sono solo separatori visivi che il compilatore ignora, i suffissi L e f sono obbligatori (ne parliamo più avanti), e char usa gli apici singoli mentre una String userebbe le virgolette doppie.
Scegliere un tipo numerico
Non ti servono quasi mai byte o short: fanno risparmiare memoria solo in array enormi. Le vere scelte sono tra int/long per i numeri interi e float/double per i decimali.
| Tipo | Dimensione | Quando usarlo |
|---|---|---|
int | 32 bit | Il default per i numeri interi (fino a circa 2,1 miliardi) |
long | 64 bit | Valori oltre circa 2 miliardi: timestamp in millisecondi, dimensioni di file |
double | 64 bit | Il default per i decimali: buona precisione |
float | 32 bit | Solo quando la memoria è scarsa e puoi sacrificare precisione |
La trappola è l'overflow. Un int ricomincia dal basso in silenzio quando supera il suo intervallo: nessun errore, solo un risultato sbagliato:
maxInt + 1 va in overflow e diventa -2147483648 perché entrambi gli operandi sono int e anche il risultato resta un int. Convertire prima uno dei due lati in long fa eseguire il calcolo a 64 bit. Quando un valore può essere grande, soprattutto i millisecondi dal 1970, usa long.
I letterali e i loro suffissi
Un letterale numerico da solo ha un tipo predefinito, e questo trae spesso in inganno. 100 è un int; 3.14 è un double. Per scrivere un letterale long o float devi aggiungere un suffisso:
Togli la L da 8_000_000_000L e il codice non compila, perché il letterale supera l'intervallo di int prima ancora di arrivare alla variabile long. Togli la f da 0.5f e Java si lamenta che un double non può essere assegnato a un float senza un cast. Il suffisso non distingue tra maiuscole e minuscole, ma usa la L maiuscola: una l minuscola sembra identica alla cifra 1.
char è un numero travestito
Un char memorizza un'unità di codice Unicode a 16 bit, quindi funziona anche come piccolo intero senza segno. Puoi farci dei calcoli e convertirlo avanti e indietro con un cast:
A volte è utile per spostare le lettere, ma non affidarti a questo per il testo: per quello c'è String. Nota che char usa gli apici singoli ('A'); le virgolette doppie ("A") creano una String di un solo carattere, che è un tipo completamente diverso.
Valori predefiniti (e la trappola delle variabili locali)
I campi e gli elementi degli array che non inizializzi ricevono un valore predefinito sensato. Ma questo vale solo per campi e posizioni degli array: le variabili locali non hanno alcun valore predefinito, e usarne una prima di assegnarle un valore è un errore di compilazione, non una sorpresa a runtime.
Se invece scrivessi int x; System.out.println(x); dentro main, il compilatore lo rifiuterebbe con "variable x might not have been initialized". Questa severità è una caratteristica utile: ti impedisce di leggere dati casuali. I valori predefiniti da ricordare: i tipi numerici 0, boolean false, char '�' e ogni tipo riferimento null.
Prossimo passo: le stringhe
String è il tipo riferimento che userai di più: testo, valori concatenati, input dell'utente. Si comporta in modo diverso dai primitivi visti qui: è un oggetto, è immutabile e confrontare stringhe ha le sue insidie. Ne parla la prossima pagina.
Domande frequenti
Quanti tipi di dati ci sono in Java?
Java ha otto tipi primitivi: byte, short, int, long, float, double, char e boolean. Tutto il resto, cioè String, gli array e qualsiasi oggetto, è un tipo riferimento. Quindi il numero di primitivi predefiniti è fisso a otto, mentre i tipi riferimento sono illimitati, perché tu (e le librerie) definite nuove classi.
Qual è la differenza tra int e long in Java?
Entrambi contengono numeri interi, ma int è a 32 bit (intervallo di circa ±2,1 miliardi) e long è a 64 bit (intervallo di circa ±9,2 trilioni). Usa int di default; passa a long quando un valore può superare i due miliardi: timestamp in millisecondi, dimensioni di file, contatori grandi. Un letterale long richiede il suffisso L, per esempio long big = 10000000000L;.
Qual è il valore predefinito di un int in Java?
Un campo int vale 0 di default, ma solo i campi e gli elementi degli array ricevono un valore predefinito. Un long vale 0L, double vale 0.0, boolean vale false, char vale '\u0000' e qualsiasi tipo riferimento vale null. Le variabili locali non ricevono alcun valore predefinito: devi assegnarne uno prima di usarle, altrimenti il codice non compila.