W3docs

Tipi di dati in Java

Esplora i tipi primitivi di Java (byte, short, int, long, float, double, char, boolean) e i tipi reference.

Java è staticamente tipizzato — ogni variabile ha un tipo noto a tempo di compilazione. I tipi si dividono in due famiglie: i primitivi (valori grezzi integrati nel linguaggio) e i tipi reference (oggetti, array, qualsiasi cosa creata con new). Questo capitolo illustra entrambi.

Gli otto tipi primitivi

I primitivi sono gli unici valori in Java che non sono oggetti. Memorizzano il loro valore direttamente nello slot di archiviazione della variabile. Java ne definisce esattamente otto:

TipoDimensioneIntervalloDefaultEsempio letterale
byte8 bitda -128 a 1270byte b = 100;
short16 bitda -32.768 a 32.7670short s = 30000;
int32 bitda -2³¹ a 2³¹-1 (≈ ±2,1 miliardi)0int i = 1_000_000;
long64 bitda -2⁶³ a 2⁶³-10Llong l = 9_000L;
float32 bitIEEE 754 singola precisione0.0ffloat f = 3.14f;
double64 bitIEEE 754 doppia precisione0.0double d = 3.14;
char16 bitUnità di codice Unicode (da U+0000 a U+FFFF)\0char c = 'A';
booleandefinito da JVMtrue oppure falsefalseboolean b = true;

Alcune cose che vale la pena ricordare:

  • int è il tipo intero predefinito. La maggior parte dei contatori e degli indici sono int. Usa long solo quando hai effettivamente bisogno di numeri superiori a circa 2 miliardi.
  • double è il tipo a virgola mobile predefinito. 3.14 senza suffisso è un double; 3.14f è un float. Usa double a meno che la pressione sulla memoria non imponga float.
  • I trattini bassi nei letterali numerici migliorano la leggibilità: 1_000_000 equivale a 1000000.
  • I valori predefiniti si applicano solo ai campi, non alle variabili locali. Una variabile locale non ha un valore predefinito — devi inizializzarla prima di leggerla.

Tipi reference

Tutto il resto — String, array, le tue classi, le classi di libreria — è un tipo reference. Una variabile di tipo reference non contiene l'oggetto stesso; contiene un riferimento (essenzialmente un puntatore) all'oggetto nello heap:

String name = "Ada";
int[] scores = new int[10];
LocalDate today = LocalDate.now();

Il valore predefinito di qualsiasi variabile reference è null — un valore speciale che significa "nessun oggetto."

String s = null;
System.out.println(s.length());  // throws NullPointerException at runtime

null è la causa di uno degli errori a runtime più comuni in Java. Il capitolo Java Exceptions spiega come gestire la NullPointerException che questo genera.

Classi wrapper

Ogni primitivo ha una classe wrapper corrispondente — un vero oggetto che racchiude il valore primitivo:

PrimitivoWrapper
byteByte
shortShort
intInteger
longLong
floatFloat
doubleDouble
charCharacter
booleanBoolean

I wrapper sono necessari quando si vogliono inserire primitivi nelle collection (che contengono solo oggetti):

List<Integer> scores = new ArrayList<>();
scores.add(42);   // autoboxed from int → Integer
int first = scores.get(0);  // unboxed from Integer → int

Java converte automaticamente tra primitivi e wrapper — questa operazione si chiama autoboxing e unboxing — quindi nella maggior parte dei casi non se ne accorge.

Una nota su String

String è un tipo reference, non un primitivo. È abbastanza speciale da avere una sintassi letterale ("testo") e l'operatore +. Le stringhe sono immutabili — una volta create, il loro contenuto non cambia mai. Ogni "modifica" restituisce una nuova stringa. Il capitolo Java Strings approfondisce l'argomento.

Scegliere un tipo

Un breve albero decisionale per l'uso quotidiano di Java:

  • Contare oggetti o usare indici di arrayint
  • Conteggi grandi (dimensioni di file, timestamp in millisecondi)long
  • DenaroBigDecimal (non double — l'arrotondamento in virgola mobile ti porterà problemi)
  • Un singolo caratterechar
  • Sì/noboolean
  • TestoString
  • Una data o un'ora → i tipi in java.time (LocalDate, Instant, Duration)

Resisti alla tentazione di "risparmiare memoria" usando byte o short per interi ordinari. Le JVM sono ottimizzate per le operazioni su int; short non usa effettivamente meno memoria nella maggior parte dei casi.

Insidie comuni

Alcuni comportamenti dei tipi sorprendono regolarmente i principianti. Conoscerli in anticipo fa risparmiare ore di debug.

L'overflow degli interi avviene silenziosamente

L'aritmetica sugli interi in Java non genera mai un'eccezione per overflow — si avvolge. Aggiungere 1 al valore massimo di int produce il valore minimo di int:

int max = Integer.MAX_VALUE;   // 2147483647
System.out.println(max + 1);   // -2147483648

Se un valore potrebbe superare circa 2,1 miliardi, usa long. Per conteggi che potrebbero far overflow anche con long, ricorri a BigInteger.

La virgola mobile non è esatta

float e double seguono lo standard IEEE 754, che non può rappresentare la maggior parte delle frazioni decimali con esattezza. L'esempio classico:

System.out.println(0.1 + 0.2);   // 0.30000000000000004

Ecco perché non dovresti mai usare double per il denaro. Usa BigDecimal (costruito da una String, ad es. new BigDecimal("0.1")) quando i valori decimali esatti sono importanti.

char è un numero

Un char è un intero senza segno a 16 bit che contiene un'unità di codice Unicode, quindi partecipa all'aritmetica:

char a = 'A';
System.out.println((int) a);   // 65
System.out.println((char) (a + 1));  // B

Confronta i wrapper con .equals(), non con ==

== su oggetti wrapper confronta i riferimenti, non i valori. A causa di una cache di autoboxing per i valori Integer piccoli (da -128 a 127), == sembra funzionare per numeri piccoli e poi fallisce per quelli grandi:

Integer a = 127, b = 127;
System.out.println(a == b);   // true  (cached)
Integer c = 128, d = 128;
System.out.println(c == d);   // false (different objects)
System.out.println(c.equals(d));  // true  (compares values)

Usa sempre .equals() per confrontare i valori wrapper. Vedi Java Type Casting per le regole sulla conversione tra questi tipi.

Una dimostrazione pratica

java— editable, runs on the server

Cosa c'è dopo

Java Type Casting mostra come convertire tra tipi numerici e tra tipi reference correlati.

Esercizio

Pratica
Quali affermazioni sui tipi di dati Java sono corrette?
Quali affermazioni sui tipi di dati Java sono corrette?
Was this page helpful?