Tipi di Dati Java Spiegati: Tipi Primitivi vs Tipi di Riferimento, Casting e Classi Wrapper

目次

1. Cosa Sono i Tipi di Dati Java? Fondamenti e Visione d’Insieme

I tipi di dati Java sono un meccanismo che determina che tipo di valore una variabile può contenere.
Java enfatizza la sicurezza dei tipi (un design che impedisce operazioni di tipo non valide al momento della compilazione), quindi ogni variabile deve avere un tipo dichiarato.

Ad esempio, osserva il codice seguente.

int number = 10;
double price = 19.8;
String name = "Java";
  • int → solo interi
  • double → solo decimali
  • String → solo stringhe

Rendendo i tipi espliciti, ottieni vantaggi come:

  • Previene assegnazioni non valide
  • Ottimizza l’uso della memoria
  • Individua bug al momento della compilazione

Se non ci fossero tipi, errori come assegnare una stringa a un intero non verrebbero scoperti fino al runtime. Java è progettato per prevenire ciò.

1.1 Cos’è un Tipo di Dato? (Definizione per Principianti)

Pensa a un tipo di dato come “il tipo di valori che una variabile è autorizzata a gestire”.

La sintassi di base è:

TypeName variableName = value;

Esempio:

int age = 25;

In questo caso:

  • int è il tipo
  • age è il nome della variabile
  • 25 è il valore

Questa è la relazione.

Se scrivi questo, otterrai un errore:

int age = "25";  // Compile-time error

Non puoi assegnare una stringa a un tipo intero. È così che funziona la sicurezza dei tipi.

Trappole comuni per i principianti

  • Supporre di poter omettere i tipi (in Java, generalmente non è possibile)
  • Confondere numeri e stringhe
  • Confondere = (assegnazione) e == (confronto)

1.2 Categorie di Tipi di Dati Java (Due Tipi)

I tipi di dati Java sono ampiamente divisi in due categorie:

  1. Primitive types
  2. Reference types

Cosa sono i tipi primitivi?

Tipi che memorizzano direttamente il valore reale.
Esempi: int, double, boolean, ecc.

Caratteristiche:

  • Efficiente in termini di memoria
  • Veloce
  • Non può contenere null

Cosa sono i tipi di riferimento?

Tipi che non memorizzano il valore stesso, ma un “riferimento” a dove il valore è memorizzato.

Esempio:

String text = "Hello";

String è un tipo di classe (un tipo di riferimento).

Caratteristiche:

  • Creati a partire da classi
  • Possono essere assegnati a null
  • Possiedono metodi (comportamento)

1.3 La Differenza nel Comportamento “Valore vs Riferimento”

Confermiamo la differenza con un semplice esempio.

int a = 10;
int b = a;
b = 20;

In questo caso:

  • a rimane 10
  • Solo b diventa 20

D’altra parte, i tipi di riferimento funzionano così:

String s1 = "Java";
String s2 = s1;

Qui, s1 e s2 possono fare riferimento allo stesso oggetto (ciò può variare a seconda dell’implementazione e delle ottimizzazioni).

Punti di difficoltà comuni

  • Confondere String con un tipo primitivo
  • Supporre che copiare un tipo di riferimento copi il valore stesso
  • Non comprendere come funziona null

1.4 Perché Capire i Tipi di Dati è Importante

Una scarsa comprensione dei tipi di dati può causare problemi come:

  • Risultati di calcolo inattesi
  • Overflow (superamento dell’intervallo di valori)
  • NullPointerException
  • Errori di conversione di tipo

Per usare Java correttamente, devi prima comprendere la visione d’insieme dei tipi di dati.

2. Tipi Primitivi (Tipi di Dati Base): Elenco e Come Usarli

I tipi primitivi sono tipi di dati che memorizzano direttamente il valore reale.
Java ha 8 tipi primitivi.

CategoryTypeSizeTypical Use
Integerbyte8bitSmall integers
Integershort16bitSmaller integers
Integerint32bitStandard integers
Integerlong64bitLarge integers
Decimalfloat32bitSingle-precision floating point
Decimaldouble64bitDouble-precision floating point (standard)
Characterchar16bitA single character
Booleanbooleantrue / false

*Le dimensioni sono fissate dalla specifica Java (non dipendono dall’ambiente).

2.1 Tipi Interi (byte / short / int / long)

Uso di base

int number = 100;
long population = 8000000000L;

Intervalli (esempi comuni)

  • byte: -128 a 127
  • short: -32.768 a 32.767
  • int: circa ±2,1 miliardi
  • long: circa ±9,22 quintilioni

Nella maggior parte dei casi, int è sufficiente.
Raramente è necessario usare byte o short solo per risparmiare memoria.

Nota importante quando si usa long

long value = 10000000000L;  // L is required

Senza la L, il letterale è trattato come un int e può causare un errore di compilazione per fuori intervallo.

Errori comuni

  • Overflow superando l’intervallo
  • Dimenticare L per i letterali long
  • Non notare l’overflow nei calcoli intint

2.2 Tipi a virgola mobile (float / double)

double price = 19.99;
float rate = 0.5f;

Regole di base

  • Di solito, usa double
  • float richiede un suffisso f
    float value = 3.14f;
    

Differenze di precisione

  • float: circa 7 cifre di precisione
  • double: circa 15 cifre di precisione

Nota importante (problemi di arrotondamento/precisione)

System.out.println(0.1 + 0.2);

Il risultato potrebbe non essere esattamente 0.3.
Questo è dovuto alla rappresentazione binaria a virgola mobile.

Calcoli monetariPer la gestione del denaro, double generalmente non è consigliato.

Usare BigDecimal è più sicuro.

Errori comuni

  • Usare double per il denaro
  • Confondere float e double
  • Confrontare decimali con ==

2.3 Tipo carattere (char)

char letter = 'A';
  • Usa apici singoli
  • Gestito con Unicode (uno standard di codifica dei caratteri)
  • Può contenere un solo carattere
    char kanji = '日';
    

Errori comuni

  • Usare doppi apici (cioè String )
  • Tentare di memorizzare più caratteri

2.4 Tipo booleano (boolean)

boolean isActive = true;
  • I valori sono solo true o false
  • Non è possibile usare 0/1 (a differenza di C)
    boolean result = (5 > 3);
    

Errori comuni

  • Tentare di assegnare un numero
  • Dimenticare di scrivere l’espressione di confronto

2.5 Note comuni per i tipi primitivi

  • Non è possibile assegnare null
  • I valori predefiniti sono impostati automaticamente per i campi, ma le variabili locali devono essere inizializzate
    int x;
    System.out.println(x);  // Compile-time error (uninitialized)
    

I tipi primitivi sono veloci e leggeri, ma hanno limitazioni come il mancato supporto a null e l’assenza di metodi.

3. Tipi di riferimento: le basi

I tipi di riferimento memorizzano non il valore stesso, ma un riferimento (indirizzo di memoria) a un oggetto.
La differenza principale rispetto ai tipi primitivi è che i “dati stessi” e la “variabile” esistono separatamente.

Guarda questo esempio:

String text = "Java";

Qui, text memorizza un riferimento all’oggetto stringa, non al valore della stringa stesso.

3.1 Tipo String (Il tipo di riferimento più comunemente usato)

String è un tipo di classe. Non è un tipo primitivo.

String name = "Taro";

Caratteristiche

  • Immutabile (non può essere modificato)
  • Può essere assegnato null
  • Ha metodi
    String str = "Hello";
    System.out.println(str.length());  // 5
    

Trappola dell’immutabilità

String s = "Java";
s.concat(" SE");
System.out.println(s);  // "Java"

concat() restituisce una nuova stringa, ma la stringa originale non viene modificata.

Uso corretto:

s = s.concat(" SE");

Errori comuni

  • Supporre che String sia un tipo primitivo
  • Usare == per il confronto di stringhe
  • Concatenazione pesante che causa problemi di prestazioni (usa StringBuilder)

3.2 Array e tipi di classe

Array

int[] numbers = {1, 2, 3};

Gli array sono anche tipi di riferimento.

int[] a = {1, 2};
int[] b = a;
b[0] = 99;

System.out.println(a[0]);  // 99

Poiché a e b fanno riferimento allo stesso array, le modifiche influenzano entrambi.

Tipi di classe

class Person {
    String name;
}

Person p = new Person();
p.name = "Ken";

new è la parola chiave usata per creare un oggetto.

3.3 Cos’è null?

null rappresenta uno stato in cui “non c’è alcun oggetto referenziato”.

String text = null;

Chiamare un metodo quando un riferimento è null provoca un errore.

text.length();  // NullPointerException

Questo è chiamato NullPointerException (NPE).

Come gestire null

if (text != null) {
    System.out.println(text.length());
}

3.4 La differenza tra == e equals()

== (confronto di riferimento)

Confronta se gli indirizzi di memoria sono gli stessi.

equals() (confronto dei contenuti)

Confronta se i contenuti sono gli stessi.

String a = new String("Java");
String b = new String("Java");

System.out.println(a == b);        // false
System.out.println(a.equals(b));   // true

Errori comuni

  • Utilizzare == per il confronto di stringhe
  • Chiamare equals() senza controllare per null
  • Confondere la copia di riferimenti e la copia di valori

3.5 Riassunto rapido: Differenze dai tipi primitivi

ItemPrimitive TypesReference Types
StoresThe value itselfA reference
nullNot allowedAllowed
MethodsNoYes
newNot neededUsually needed

I tipi di riferimento sono flessibili, ma devi fare attenzione alla gestione di null e ai riferimenti condivisi.

4. Classi Wrapper e Autoboxing

Le classi wrapper sono classi che ti permettono di trattare i valori primitivi come oggetti.
In Java, le collezioni (come List e Map) possono memorizzare solo tipi di riferimento, quindi non puoi memorizzare direttamente i primitivi. Le classi wrapper esistono per questo scopo.

4.1 Classi Wrapper Comuni

Primitive TypeWrapper Class
byteByte
shortShort
intInteger
longLong
floatFloat
doubleDouble
charCharacter
booleanBoolean

Esempio:

Integer number = 10;
Double price = 19.99;

Poiché le classi wrapper sono tipi di riferimento, possono contenere null.

Integer value = null;  // OK

4.2 Cos’è l’Autoboxing?

Boxing significa convertire un tipo primitivo in una classe wrapper.

Da Java 5, questa conversione può avvenire automaticamente.

Integer num = 10;  // autoboxing

Internamente, è equivalente a:

Integer num = Integer.valueOf(10);

4.3 Cos’è l’Unboxing?

Unboxing converte una classe wrapper di nuovo in un tipo primitivo.

Integer num = 20;
int value = num;  // auto-unboxing

Internamente:

int value = num.intValue();

4.4 Quando Hai Bisogno delle Classi Wrapper

1. Quando usi le collezioni

import java.util.ArrayList;

ArrayList<Integer> list = new ArrayList<>();
list.add(10);  // autoboxing

Non puoi usare ArrayList<int>.

2. Quando devi gestire null

Integer score = null;

I tipi primitivi non possono essere null.

4.5 Note ed Errori Comuni

1. Eccezione durante l’unboxing di null

Integer num = null;
int value = num;  // NullPointerException

Si verifica un’eccezione durante l’auto-unboxing.

2. Confrontare con ==

Integer a = 1000;
Integer b = 1000;

System.out.println(a == b);  // may be false

Poiché si tratta di oggetti, == confronta i riferimenti.
Usa equals() per il confronto dei contenuti.

a.equals(b);

3. Impatto sulle prestazioni

Le classi wrapper possono comportare la creazione di oggetti,
quindi i calcoli pesanti potrebbero essere più lenti rispetto all’uso di tipi primitivi.

4.6 Scegliere Tra Tipi Primitivi e Classi Wrapper

  • Calcoli numerici → tipi primitivi
  • Memorizzazione in collezioni → classi wrapper
  • Gestione di null → classi wrapper

Se ricordi queste linee guida, non esiterai nel lavoro reale.

5. Conversione di Tipo (Casting): Le Basi

In Java, quando lavori con valori di diversi tipi di dati, usi la conversione di tipo (casting).
Ci sono due tipi principali:

  • Conversione implicita (conversione di ampliamento)
  • Conversione esplicita (conversione di restringimento)

5.1 Conversione Implicita (Ampliamento)

Le conversioni da un tipo con intervallo più piccolo a un tipo con intervallo più grande avvengono automaticamente.

int num = 100;
long bigNum = num;  // automatic conversion

È sicuro perché espande l’intervallo numerico.

Ordine di conversione (esempio relativo agli interi)

byte → short → int → long → float → double

Esempio

int a = 10;
double b = a;  // OK

Note

  • La precisione è preservata in molti casi, ma può verificarsi un arrotondamento con float o double.
  • char può essere convertito come valore intero.
    char c = 'A';
    int code = c;  // 65
    

5.2 Conversione Esplicita (Restringimento)

Quando converti da un tipo più grande a uno più piccolo, devi eseguire il cast esplicitamente.

double price = 19.99;
int rounded = (int) price;

Il risultato è:

rounded = 19

La parte frazionaria viene troncata.

Sintassi

(TargetType) variable

5.3 Esempio di Perdita di Dati

int big = 1000;
byte small = (byte) big;
System.out.println(small);

Il risultato non è “imprevedibile”, ma piuttosto avvolto per adattarsi all’intervallo target.
Qui, 1000 supera l’intervallo byte, quindi il valore cambia.

Errori comuni

  • Pensare che causerà un errore → in realtà, il valore cambia
  • Assumere che sia sempre sicuro → può verificarsi perdita di dati

5.4 Una Trappola: Divisione Intera

int a = 5;
int b = 2;
double result = a / b;
System.out.println(result);

Il risultato è:

2.0

La divisione intera viene eseguita come un’operazione intera.

Approccio corretto:

double result = (double) a / b;

Risultato:

2.5

5.5 Note sul Confronto di Decimali

double x = 0.1 + 0.2;
System.out.println(x == 0.3);  // may be false

Questo è dovuto a problemi di precisione a virgola mobile.

Un confronto più sicuro

Math.abs(x - 0.3) < 0.000001

5.6 Casting dei Tipi di Riferimento

È possibile anche fare il casting dei tipi di riferimento (quando esiste una relazione di ereditarietà).

Object obj = "Java";
String str = (String) obj;

Il casting a un tipo errato causa un’eccezione.

Integer num = (Integer) obj;  // ClassCastException

Riepilogo degli Errori Comuni

  • Le conversioni fuori intervallo cambiano i valori
  • Non accorgersi della divisione intera
  • Confrontare decimali con ==
  • Forzare casting di riferimenti non validi

Il casting spesso non attiva errori in tempo di compilazione, quindi i malintesi possono facilmente portare a bug.

6. Guida Pratica alla Selezione dei Tipi (Per Non Esitare al Lavoro)

Ora che hai capito come funzionano i tipi di dati Java, una domanda comune nel mondo reale è: “Quale tipo dovrei usare?” Questa sezione organizza criteri di decisione pratici.

6.1 Perché int e double Sono Di Solito Sufficienti

Usa int per gli interi (di default)

int count = 100;

Motivi:

  • L’intervallo a 32 bit è sufficiente per la maggior parte dei casi
  • Più facile per la JVM da ottimizzare
  • Leggibile e standard

Di solito non è necessario forzare l’uso di byte o short.
Scegliere tipi più piccoli solo per risparmiare memoria è solitamente solo per casi speciali (come array enormi).

Usa double per i decimali (di default)

double rate = 0.75;

Ha una precisione superiore a float ed è la scelta standard.
A meno che tu non abbia un motivo chiaro, scegli double.

6.2 Perché Dovresti Usare BigDecimal per i Soldi

Questo codice è rischioso per i soldi:

double price = 0.1 + 0.2;

A causa degli errori a virgola mobile, potresti non ottenere un valore esatto.

Approccio corretto:

import java.math.BigDecimal;

BigDecimal a = new BigDecimal("0.1");
BigDecimal b = new BigDecimal("0.2");
BigDecimal result = a.add(b);

Perché passare stringhe?

new BigDecimal(0.1);  // not recommended

Creare da un double può portare con sé il suo errore di precisione.

Errori comuni

  • Gestire i soldi con double
  • Usare new BigDecimal(doubleValue)
  • Dimenticare le regole di arrotondamento

6.3 Le Collezioni Richiedono Classi Wrapper

import java.util.ArrayList;

ArrayList<Integer> list = new ArrayList<>();
list.add(10);

Non è possibile usare tipi primitivi direttamente.

ArrayList<int> list;  // Compile-time error

Motivo:

  • I generics (collezioni type-safe) supportano solo tipi di riferimento

6.4 Decidi in Base al Fatto che Hai Bisogno di null

Nessun null necessario → tipi primitivi

int age = 0;

null necessario → classi wrapper

Integer age = null;

Nelle integrazioni con database o input di form, potresti aver bisogno di gestire null.

6.5 Linee Guida di Base sulle Prestazioni

  • Calcoli → tipi primitivi
  • Collezioni → classi wrapper
  • Evita di creare wrapper all’interno di loop stretti

Esempio (non raccomandato):

for (Integer i = 0; i < 1000000; i++) { }

Usare tipi primitivi è più efficiente.

6.6 Tabella di Riepilogo: Tipi Raccomandati per Caso d’Uso

Use CaseRecommended Type
Typical integersint
Typical decimalsdouble
MoneyBigDecimal
Boolean checksboolean
StringsString
Storing in collectionsWrapper classes

Errori Comuni nel Mondo Reale

  • Scegliere tipi inutilmente piccoli
  • Usare double per i soldi
  • Progettare senza considerare null
  • Eccezioni di auto-unboxing dalle classi wrapper

La selezione del tipo è una parte fondamentale del design. Se procedi con ambiguità, il costo di correggere i problemi in seguito aumenta significativamente.

7. Riepilogo dei Tipi di Dati Java (Con Tabelle)

Riassumiamo tutto in un formato che risponde rapidamente alle intenzioni di ricerca comuni.
I tipi di dati Java sono divisi in “tipi primitivi” e “tipi di riferimento.”

7.1 Elenco dei Tipi Primitivi

TypeSizeDefault (fields)Typical Use
byte8bit0Small integers
short16bit0Smaller integers
int32bit0Standard integers
long64bit0LLarge integers
float32bit0.0fSingle-precision floating point
double64bit0.0dStandard floating point
char16bit‘\u0000’A single character
booleanfalseBoolean value

*Le variabili locali non sono inizializzate automaticamente.

Punti chiave

  • Per calcoli numerici, usa di default int / double
  • Per i soldi, usa BigDecimal
  • null non è consentito
  • Nessun metodo

7.2 Panoramica dei Tipi di Riferimento

Tipi di riferimento tipici:

  • String
  • Array (ad es., int[] )
  • Tipi di classe (classi personalizzate)
  • Classi wrapper (ad es., Integer )
  • Collezioni (List, Map, ecc.)

Riepilogo delle caratteristiche

ItemReference Types
Can assign nullYes
MethodsAvailable
new keywordUsually needed
Comparisonequals() recommended

7.3 Confronto Finale: Primitivi vs Riferimento

PerspectivePrimitive TypesReference Types
StoresDirectlyBy reference
Memory efficiencyHighSomewhat lower
nullNoYes
SpeedFastSomewhat slower
Main useCalculationsObject handling

7.4 L’Impostazione Minimale che i Principianti Dovrebbero Imparare Prima

Inizia con questi quattro tipi:

  • int
  • double
  • String
  • boolean

Con questi, puoi creare programmi di base.

7.5 Errori Comuni Generali

  1. Confrontare String con ==
  2. Usare double per i soldi
  3. Non notare la divisione intera
  4. Dimenticare i controlli null
  5. Dimenticare L per i letterali long
  6. Unboxing null nelle classi wrapper

Evitare questi da soli ridurrà significativamente gli errori dei principianti.

7.6 Considerazioni Finali

  • Java è un linguaggio con tipi sicuri
  • Comprendere i tipi di dati è la base di tutto il codice
  • I tipi primitivi sono per calcoli veloci
  • I tipi di riferimento sono per gestire oggetti
  • Scegliere il tipo giusto influisce direttamente sulla qualità

FAQ

Q1. Quanti tipi di dati Java ci sono?

Risposta:
Ci sono 8 tipi primitivi. I tipi di riferimento possono essere infiniti (classi, array, interfacce, ecc.). È importante prima comprendere gli 8 tipi primitivi.

Q2. String è un tipo primitivo?

Risposta:
No. String è un tipo di classe (un tipo di riferimento). È trattato come un oggetto e può essere assegnato null.

Q3. Qual è la differenza tra int e Integer?

Risposta:
int è un tipo primitivo. Integer è una classe wrapper (un tipo di riferimento). Integer può contenere null, ma l’auto-unboxing può lanciare un’eccezione.

Q4. Posso usare double per calcoli con denaro?

Risposta:
Tecnicamente sì, ma non è raccomandato. Possono verificarsi problemi di precisione a virgola mobile, quindi usare BigDecimal è più sicuro.

Q5. Perché la divisione di interi non produce un decimale?

Risposta:
Perché le operazioni sugli interi vengono eseguite usando tipi interi, la parte frazionaria viene troncata. Se hai bisogno di un risultato decimale, cast uno degli operandi a double.

Q6. Cos’è null?

Risposta:
Rappresenta uno stato in cui nessun oggetto è referenziato. Chiamare un metodo su null causa una NullPointerException.

Q7. Qual è la differenza tra == e equals()?

Risposta:
== confronta i riferimenti (indirizzi di memoria). equals() confronta i contenuti. Per il confronto di stringhe, usa equals().

Q8. Quali tipi dovrebbero imparare prima i principianti?

Risposta:
Dai priorità a int, double, String e boolean. Questi sono i tipi core più comunemente usati nel lavoro reale.