L’autore ha selezionato il Fondo per il Software Libero e Open Source per ricevere una donazione come parte del programma Scrivi per le Donazioni.
Introduzione
Java è un linguaggio di programmazione staticamente tipizzato. Ciò significa che quando si crea una variabile, è necessario specificare anche il suo tipo di dato, che è il tipo di informazione che memorizza. Questo è in contrasto con i linguaggi dinamicamente tipizzati, come PHP. Con i linguaggi dinamicamente tipizzati, non è necessario specificare il tipo di dato di una variabile, il che può sembrare un sollievo.
Tuttavia, conoscere i tipi di dati e usarli in modo appropriato consente agli sviluppatori di ottimizzare il proprio codice perché ogni tipo di dato ha requisiti specifici di risorse. Inoltre, se si specifica un tipo di dato e si cerca di memorizzare un tipo diverso, ad esempio per errore, non sarà possibile compilare il codice. Pertanto, con i linguaggi staticamente tipizzati, è possibile rilevare gli errori ancora prima di qualsiasi test.
Java ha due tipi di dati: primitivi e di riferimento (anche noti come non primitivi). In questo tutorial, userai variabili per memorizzare e utilizzare informazioni in un programma Java al fine di apprendere alcuni dei tipi di dati comunemente utilizzati in Java. Questa non è una panoramica esaustiva di tutti i tipi di dati, ma questa guida ti aiuterà a familiarizzare con le opzioni disponibili in Java.
Prerequisiti
Per seguire questo tutorial, avrai bisogno di:
-
Un ambiente in cui è possibile eseguire programmi Java per seguire gli esempi. Per configurarlo sul tuo computer locale, avrai bisogno dei seguenti elementi:
- Java (versione 11 o superiore) installato sul tuo computer, con il compilatore fornito dal Java Development Kit (JDK). Per Ubuntu e Debian, segui i passaggi per l’Opzione 1 nel nostro tutorial, Come Installare Java con Apt su Ubuntu 22.04. Per altri sistemi operativi, inclusi Mac e Windows, consulta le opzioni di download per l’installazione di Java.
- Per compilare ed eseguire gli esempi di codice, questo tutorial utilizza Java Shell, un Read-Evaluate-Print Loop (REPL) eseguito dalla riga di comando. Per iniziare con JShell, consulta la guida Introduzione a JShell.
-
Familiarità con Java e la programmazione orientata agli oggetti, che puoi trovare nel nostro tutorial, Come Scrivere il Tuo Primo Programma in Java.
Tipi Primitivi
I tipi primitivi di Java sono i tipi di dati più semplici e di base in Java. Rappresentano valori grezzi come numeri e caratteri. I tipi di dati primitivi più utilizzati sono int
(interi), boolean
(valori booleani) e char
(caratteri). Puoi trovare il resto nella documentazione ufficiale sui tipi di dati di Java.
Interi
Gli interi possono essere sia numeri interi negativi che positivi. In Java, userai int
per memorizzarli. int
può ospitare numeri sufficientemente grandi per la maggior parte degli scopi: da -2.147.483.648
a 2.147.483.647
.
Diamo un’occhiata a come viene utilizzato int
in un esempio:
int theAnswer = 42;
I tipi primitivi iniziano sempre con una lettera minuscola (int
). Le regole di sintassi di Java richiedono che tu specifichi prima il tipo di dati (int
) e poi il suo nome (theAnswer
). Dopo di che, assegni il valore 42
con il segno uguale (=
) alla variabile.
Indipendentemente dal tipo di dati, si utilizza una variabile specificando direttamente il suo nome senza anteporre alcun carattere speciale. Ciò perché Java può riconoscerla come una variabile.
Nota: Il nome della variabile theAnswer
e tutte le altre variabili in questo tutorial sono scritte in Camel case. Anche se non c’è un requisito rigoroso per usarlo, questa è la convenzione di denominazione accettata in Java.
Una volta dichiarata la variabile, è possibile utilizzarla facendo riferimento ad essa in un metodo come segue:
int theAnswer = 42;
System.out.println("The answer to all questions is " + theAnswer);
Nella seconda riga, si stampa theAnswer
sulla console utilizzando il metodo integrato println
del package System.out
. Questo è il modo più semplice per testare una variabile per assicurarsi che sia stata dichiarata come previsto.
Per vedere questo codice in azione, utilizzare lo strumento Java Shell. Dopo aver installato Java, aprire un terminale o prompt dei comandi sul computer locale e digitare jshell
:
- jshell
Il risultato sarà simile al seguente:
Output| Welcome to JShell -- Version 11.0.16
| For an introduction type: /help intro
jshell>
È possibile incollare gli esempi di codice da questo tutorial nella console. Una volta terminato, è possibile uscire da jshell
digitando /exit
.
Per dichiarare e utilizzare int
, incollare le seguenti righe nella console di jshell
:
- int theAnswer = 42;
- System.out.println("The answer to all questions is " + theAnswer);
Vedrete il seguente output:
OutputtheAnswer ==> 42
The answer to all questions is 42
Questo output conferma che avete impostato correttamente la variabile int
theAnswer
a 42 (theAnswer ==> 42
). Avete anche utilizzato con successo theAnswer
passandola a un metodo, e il metodo ha prodotto il valore della variabile previsto.
Booleano
Booleano rappresenta valori true
o false
. In Java, si utilizza boolean
per memorizzarli. Ad esempio, creiamo una variabile boolean
che definisce se Java è divertente:
boolean isJavaFun = true;
Si definisce la variabile isJavaFun
come true
. Il valore alternativo per boolean
è false
.
Utilizzando la variabile sopra, è possibile stampare la frase Java is fun: true
in questo modo:
- boolean isJavaFun = true;
- System.out.println("Java is fun: " + isJavaFun);
Eseguendo queste righe in jshell
, si otterrà l’output seguente:
OutputisJavaFun ==> true
Java is fun: true
Simile all’esempio di int
, il metodo println
stamperà l’argomento fornito tra parentesi. Il segno più (+
) concatena o unisce la stringa “Java is fun: ” con la variabile isJavaFun
, in modo che in realtà sia un unico argomento: la stringa Java is fun: true
.
Caratteri
Per memorizzare un singolo carattere alfanumerico, si utilizza char
. Ad esempio:
char firstLetter = 'a';
Nota che la lettera a
è racchiusa tra apici singoli. Gli apici singoli possono essere utilizzati solo per valori char
. Gli apici doppi sono utilizzati per le stringhe, come si imparerà in seguito.
char
non sembra essere un tipo particolarmente utile perché è improbabile che avrai bisogno di una variabile assegnata a un singolo carattere. Tuttavia, char
è utilizzato come mattoncino per le classi di stringhe di caratteri come String
, che sono fondamentalmente una collezione di valori char
.
Come hai visto in questa sezione, la dichiarazione e l’uso di variabili di tipo primitivo sono semplici perché rappresentano valori semplici come interi. Questi valori sono pronti per essere utilizzati e non richiedono operazioni aggiuntive come la creazione di oggetti, l’invocazione di metodi, e così via.
Tipi di Riferimento
Nel primo tutorial di questa serie, Come Scrivere il Tuo Primo Programma in Java, hai appreso che il codice Java è organizzato in classi e che queste classi sono utilizzate come modelli per creare oggetti. Quando tali oggetti vengono assegnati a variabili, stai puntando o facendo riferimento a questi oggetti. In questi casi, le variabili sono classificate come tipi di riferimento. Queste variabili sono anche conosciute come non primitive perché le variabili di tipo primitivo non possono puntare agli oggetti.
Gli oggetti sono potenti perché hanno proprietà avanzate e sono in grado di agire quando si attivano i loro metodi. Tuttavia, senza variabili che puntano a essi, questi oggetti sono inaccessibili e praticamente inutilizzabili. Ecco perché le variabili di tipo riferimento sono essenziali per Java e la programmazione orientata agli oggetti nel suo complesso.
Nota: I tipi di riferimento puntano agli oggetti creati dalle classi. Per evitare confusione, il tipo di riferimento e l’oggetto creato saranno della stessa classe negli esempi seguenti.
Tuttavia, nei programmi complessi, questo è raramente il caso. In Java, un interfaccia è un insieme di requisiti per un comportamento specifico, e questi requisiti possono essere soddisfatti da una o più classi. Una classe che soddisfa i requisiti di un’interfaccia si dice che implementa questa interfaccia. Quindi, nei programmi complessi, è comune dichiarare una variabile con il tipo di riferimento di un’interfaccia. In questo modo, si specifica il comportamento che la variabile dovrebbe esibire senza legarla a un’implementazione concreta di questo comportamento. Ciò consente di cambiare facilmente l’implementazione a cui punta la variabile senza dover modificare il modo in cui viene utilizzata la variabile. Questo concetto complesso fa parte di un argomento più avanzato su ereditarietà e polimorfismo, che sarà un tutorial separato nella nostra serie Java.
Mentre ci sono solo alcuni tipi primitivi, i tipi di riferimento sono praticamente illimitati perché non c’è un limite al numero di classi (e interfacce), e ogni classe rappresenta un tipo di riferimento. In Java ci sono molte classi incorporate che forniscono funzionalità essenziali. Le più utilizzate si trovano nel package principale java.lang
. Ne rivedrai alcune in questa sezione.
La classe String
La classe String
rappresenta una combinazione di caratteri che costituiscono una stringa. Per dichiarare una variabile di tipo String
, o di qualsiasi altro tipo di riferimento, specifichi prima il suo tipo seguito dal suo nome. Dopo di che, assegni un valore con il segno di uguale. Finora, è simile a lavorare con tipi primitivi. Tuttavia, i tipi di riferimento puntano a oggetti, quindi devi creare un oggetto se non ne è stato ancora creato uno. Ecco un esempio:
String hello = new String("Hello");
hello
è il nome della variabile con tipo di riferimento String
. Lo assegni a un nuovo oggetto String
. Il nuovo oggetto String
viene creato con la parola chiave new
insieme al nome della classe — String
in questo caso. La classe String
inizia con una lettera maiuscola. Per convenzione, tutte le classi e quindi i tipi di riferimento iniziano con una lettera maiuscola.
Ogni classe ha un metodo speciale chiamato un costruttore che viene utilizzato per creare nuovi oggetti. Puoi invocare questo costruttore aggiungendo parentesi (()
) alla fine del nome della classe. Il costruttore può accettare parametri, come nell’esempio sopra, dove il parametro "Ciao"
è applicato al costruttore per String
.
Per confermare che la variabile hello
si comporti come previsto, passala nuovamente al metodo println
in questo modo:
- String hello = new String("Hello");
- System.out.println(hello);
Eseguire queste righe in jshell
produrrà il seguente output:
Outputhello ==> "Hello"
Hello
Questa volta, l’output conferma che la variabile hello
è impostata su Ciao
. Dopo di che, lo stesso Ciao
viene stampato su una nuova riga, confermando che il metodo println()
lo ha elaborato.
Classi Wrapper
Nella sezione precedente, hai lavorato con il tipo di riferimento String
, che viene utilizzato frequentemente. Altri tipi di riferimento popolari sono le cosiddette classi wrapper per tipi primitivi. Una classe wrapper avvolge o contiene dati primitivi, da qui il suo nome. Tutti i tipi primitivi hanno controparti wrapper, ed ecco alcuni esempi:
Integer
: Per avvolgere valoriint
.Character
: Per avvolgere valorichar
.Boolean
: Per avvolgere valoriboolean
.
Questi wrapper esistono per consentire di aggiornare un semplice valore primitivo a un potente oggetto. Ogni wrapper ha metodi pronti all’uso relativi ai valori che è progettato per memorizzare.
Come esempio, esplorerai Integer
. Nella sezione precedente, hai creato un oggetto String
con la parola chiave new
. Tuttavia, alcune classi forniscono, e addirittura incoraggiano, l’uso di metodi speciali per acquisire oggetti da loro, e Integer
è uno di questi. Nel caso di Integer
, l’uso di un metodo speciale riguarda principalmente l’ottimizzazione delle risorse, ma in altri casi potrebbe riguardare la semplificazione della costruzione di oggetti complessi.
Nell’esempio seguente, crei una variabile Integer
chiamata theAnswer
con il valore 42
utilizzando il metodo valueOf
:
- Integer theAnswer = Integer.valueOf(42);
- System.out.println(theAnswer);
In jshell
, otterrai il seguente output:
OutputtheAnswer ==> 42
42
Chiamando il metodo valueOf(42)
di Integer
, istruisci Java a fornirti un oggetto con questo valore. Nel backstage, Java verificherà se esiste già un oggetto con tale valore nella sua cache. Se esiste, l’oggetto sarà collegato alla variabile theAnswer
. Se non esiste, verrà creato un nuovo oggetto per la variabile theAnswer
.
Molte classi integrate forniscono tali metodi per motivi di prestazioni, e il loro utilizzo è consigliato, se non obbligatorio. Nel caso di Integer
, potresti ancora creare un oggetto con la parola chiave new
, ma otterrai un avviso di deprecazione.
Oltre alla classe String
e ai wrapper, ci sono anche altri utili tipi di riferimento built-in, che puoi trovare nel riassunto del pacchetto java.lang. Per comprendere appieno alcuni di questi tipi di riferimento più avanzati, è necessaria un’ulteriore spiegazione o conoscenza preliminare. Ecco perché ne parleremo nei prossimi tutorial della serie Java.
Literali
I letterali rappresentano valori fissi che possono essere utilizzati direttamente nel codice e quindi possono essere assegnati sia ai tipi primitivi che ai tipi di riferimento. Esistono alcuni tipi di letterali, che possono essere categorizzati come segue.
Letterali di Tipo Primitivo
Hai già utilizzato alcuni letterali nella sezione sui tipi primitivi. Per ogni tipo primitivo, c’è un letterale, come quelli dei nostri esempi: 42
, 'a'
, e true
. Gli interi come 42
sono letterali interi. Allo stesso modo, i caratteri come 'a'
sono letterali carattere, e true
e false
sono letterali booleani.
I tipi primitivi letterali possono anche essere utilizzati per creare valori per i tipi di riferimento. Il letterale int
è stato utilizzato per creare un oggetto Integer
con il codice Integer.valueOf(42)
. C’è anche una forma abbreviata per questo, e puoi assegnare il valore direttamente in questo modo:
Integer theAnswer = 42;
42
è un letterale intero, proprio come qualsiasi numero intero, e puoi assegnarlo direttamente alla variabile theAnswer
senza ulteriori istruzioni. È comune vedere un Integer
dichiarato in questo modo perché è conveniente.
Questo approccio abbreviato funziona anche per altri tipi primitivi letterali e i loro tipi di riferimento corrispondenti come Boolean
, ad esempio:
Boolean isFun = true;
true
è il letterale, che viene assegnato direttamente alla variabile isFun
di tipo Boolean
. C’è anche un letterale false
, che puoi assegnare allo stesso modo.
Il Letterale di Stringa
C’è anche un letterale speciale per il tipo di riferimento String
, ed è riconosciuto dalle virgolette doppie che circondano il suo valore. In questo esempio, è "Ciao, Mondo!"
:
String helloWorld = "Hello, World!";
Utilizzare i letterali è più semplice e più breve, ed è per questo che molti programmatori lo preferiscono. Tuttavia, è comunque possibile dichiarare una variabile String
con un nuovo oggetto String
, come hai già fatto nella sezione dei tipi di riferimento.
Il Letterale Null
C’è un altro letterale importante: null
, che rappresenta l’assenza di un valore o la non esistenza di un oggetto. Null
ti consente di creare un tipo di riferimento e di puntarlo a null
invece di puntarlo a un oggetto. null
può essere utilizzato per tutti i tipi di riferimento, ma non per i tipi primitivi.
C’è una nota da tenere presente con il letterale null
: puoi dichiarare variabili con esso, ma non puoi utilizzare queste variabili fino a quando non assegni un valore idoneo e non nullo. Se provi a utilizzare una variabile di tipo riferimento con un valore null
, otterrai un errore. Ecco un esempio:
- String initiallyNullString = null;
- System.out.println("The class name is: " + initiallyNullString.getClass());
Quando provi ad eseguire questo codice in jshell
, vedrai un errore simile al seguente:
OutputinitiallyNullString ==> null
| Exception java.lang.NullPointerException
| at (#4:1)
A seconda del tuo sistema operativo e della versione di Java, la tua output potrebbe variare.
Viene lanciato l’errore java.lang.NullPointerException
perché stai cercando di invocare il metodo getClass()
di String
(che restituisce il nome della classe) sulla variabile initiallyNullString
(che punta a un oggetto nullo).
Nota: Per semplicità, chiamiamo l’eccezione java.lang.NullPointerException
un errore, anche se tecnicamente è un’eccezione. Per ulteriori informazioni su eccezioni ed errori, consulta il tutorial Gestione delle eccezioni in Java.
Per risolvere l’errore, devi riassegnare il valore di initiallyNullString
in questo modo:
- String initiallyNullString = null;
- initiallyNullString = "not null any longer";
- System.out.println("The class name is: " + initiallyNullString.getClass());
Il nuovo codice corretto stamperà il seguente output:
OutputinitiallyNullString ==> null
initiallyNullString ==> "not null any longer"
The class name is: class java.lang.String
L’output sopra mostra come initiallyNullString
sia prima null
, poi diventi un nuovo oggetto String
contenente "non più nullo"
. Successivamente, quando il metodo getClass()
viene invocato sull’oggetto istanziato, ottieni java.lang.String
, in cui String
è il nome della classe e java.lang
è il suo package. Infine, viene stampato un messaggio completo e significativo: "Il nome della classe è: class java.lang.String"
.
Queste dichiarazioni di valore null
sono più comuni per il codice legacy. Sono stati usati per creare una variabile prima e successivamente assegnarle il suo vero valore, di solito passando attraverso qualche logica che determina quest’ultimo. Tuttavia, a partire dalla versione 8 di Java, esiste un nuovo tipo di riferimento chiamato Optional, che è più adatto per i casi in cui null
è stato utilizzato in precedenza.
Local Variable Type Inference
Fino ad ora, hai utilizzato alcuni dei tipi di dati comuni in Java per definire le variabili. Tuttavia, Java 10 ha introdotto una nuova funzionalità chiamata inferenza del tipo di variabile locale, che ti permette di utilizzare la parola chiave var
davanti a una nuova variabile. Con questa funzionalità, Java dedurrà (ovvero, indovinerà automaticamente) il tipo di dati dal contesto locale. L’inferenza del tipo è controversa poiché contrasta con la verbosità precedentemente spiegata nella definizione delle variabili. I vantaggi e gli svantaggi di tale funzionalità sono oggetto di disputa, ma il fatto è che altri linguaggi a tipizzazione statica, come C++, supportano l’inferenza del tipo.
In ogni caso, l’inferenza del tipo non può sostituire completamente l’uso dei tipi di dati perché funziona solo con le variabili locali, ovvero le variabili all’interno di un metodo. Vediamo un esempio con var
:
- var hello = "Hello";
- System.out.println(hello);
Dichiari la variabile hello
con la parola chiave var
per istruire Java a rilevarne il tipo di dati. Successivamente, la stampi sulla console nel modo usuale per confermare che funziona come previsto:
Ouputhello ==> "Hello"
Hello
Questo esempio funzionerà fintanto che la tua installazione di Java (più specificamente, il JDK) è di versione superiore alla 10. La parola chiave var
non è supportata nelle versioni più vecchie.
Il processo di inferenza del tipo avviene durante il processo di compilazione, cioè quando si compila il codice. Il processo di compilazione trasforma il codice sorgente di testo normale in codice macchina e applica varie ottimizzazioni, compresa l’inferenza del tipo. Questo assicura che la quantità corretta di memoria di sistema sia disponibile per le variabili a tipo inferito. Pertanto, il codice macchina eseguito dopo la compilazione è completamente ottimizzato, come se avessi specificato manualmente tutti i tipi di dati.
In questo esempio, la parola chiave var
funziona perché la variabile è locale, e il tipo di dati var
funziona solo con le variabili locali. Le variabili locali sono definite all’interno dei metodi e sono accessibili solo all’interno dei metodi, motivo per cui vengono chiamate “locali”.
Per dimostrare che var
può essere utilizzato solo per le variabili locali, prova a collocarlo al di fuori del metodo principale, come segue:
- public class Hello {
- var hello = "Hello";
- public static void main(String[] args) {
- // example code
- }
- }
Quando incolli il codice sopra in jshell
, otterrai il seguente errore:
Output| Error:
| 'var' is not allowed here
| var hello = "Hello";
| ^-^
var
non è consentito lì perché hello
è al di fuori di un metodo e non è più considerato locale. Pertanto, l’inferenza del tipo non funziona per le variabili non locali perché il contesto non può essere utilizzato in modo affidabile per rilevare il tipo di dati.
Anche se l’uso di var
può essere impegnativo e non è obbligatorio, è probabile che tu lo incontri, quindi è utile saperne qualcosa.
Parole Chiave Riservate
Quando si dichiarano le variabili in Java, c’è una regola importante in più da conoscere. Ci sono parole chiave riservate che non è possibile utilizzare come nomi di variabili. Ad esempio, non è possibile dichiarare una variabile primitiva di tipo int
e chiamarla new
in questo modo:
- int new = 1;
Se si prova questo esempio, si otterranno errori di compilazione perché new
è una parola chiave riservata.
Output| Error:
| '.class' expected
| int new = 1;
| ^
| Error:
| <identifier> expected
| int new = 1;
| ^
| Error:
| '(' or '[' expected
| int new = 1;
| ^
| Error:
| unexpected type
| required: value
| found: class
| int new = 1;
| ^--^
| Error:
| missing return statement
| int new = 1;
| ^----------^
La parola chiave new
è utilizzata per creare nuovi oggetti e Java non si aspetta di trovarla in questa posizione. Nella lista degli errori nell’output precedente, la prima parte è la più importante:
Output| Error:
| '.class' expected
| int new = 1;
| ^
L’errore '.class' expected
significa che quando si utilizza la parola chiave new
, Java si aspetta che segua una classe. A questo punto, Java non è in grado di interpretare l’istruzione e seguono il resto degli errori.
Il resto delle parole chiave riservate, come abstract
, continue
, default
, for
, e break
, hanno significati specifici in Java e non possono essere utilizzate come nomi di variabili. L’elenco completo delle parole chiave riservate può essere trovato sulla pagina delle Java Language Keywords. Anche se non si ricordano tutte le parole chiave riservate, è possibile utilizzare gli errori di compilazione per identificare il problema.
Conclusioni
In questo tutorial hai imparato sui tipi di dati primitivi e di riferimento in Java, che è un argomento complesso ma essenziale. Prenditi il tuo tempo per esercitarti e passare più volte gli esempi. Prova a cambiare alcuni dei tipi di dati e dei valori. Presta attenzione a quando vengono generati errori e quando no, al fine di sviluppare un senso per l’esecuzione di codice con successo.
Per saperne di più su Java, dai un’occhiata alla nostra serie Come Programmare in Java.
Source:
https://www.digitalocean.com/community/tutorials/understanding-data-types-in-java