Ciao! Durante l'utilizzo di JavaRush, ti sei imbattuto in tipi primitivi più di una volta. Ecco un breve elenco di ciò che sappiamo su di loro:
Ma, oltre ai valori, i tipi differiscono anche per la dimensione della memoria.
La tipologia
- Non sono oggetti e rappresentano un valore archiviato in memoria
- Esistono diversi tipi di tipi primitivi:
- Numeri interi -
byte
,short
,int
,long
- Numeri in virgola mobile (frazionari) -
float
edouble
- Booleano -
boolean
- Simbolico (per indicare lettere e numeri) -
char
- Numeri interi -
- Ognuno di essi ha il proprio intervallo di valori:
Tipo primitivo | Dimensioni in memoria | Intervallo di valori |
---|---|---|
byte | 8 bit | da -128 a 127 |
corto | 16 bit | da -32768 a 32767 |
car | 16 bit | da 0 a 65536 |
int | 32 bit | da -2147483648 a 2147483647 |
lungo | 64 bit | da -9223372036854775808 a 9223372036854775807 |
galleggiante | 32 bit | da (2 alla potenza -149) a ((2-2 alla potenza -23)*2 alla potenza 127) |
Doppio | 64 bit | da (-2 alla potenza di 63) a ((2 alla potenza di 63) - 1) |
booleano | 8 (se utilizzato in array), 32 (se utilizzato in non array) | vero o falso |
int
ci vuole più di byte
. A long
- più di short
. La quantità di memoria occupata dai primitivi può essere paragonata alle bambole nidificanti: all'interno della bambola nidificante c'è spazio libero. Più grande è la bambola da nidificazione, maggiore è lo spazio. long
Possiamo facilmente metterne uno più piccolo all'interno di una grande bambola da nidificazione int
. Si adatta facilmente e non è necessario fare nulla in più. In Java, quando si lavora con le primitive, questa si chiama conversione automatica. In un altro modo si chiama espansione. Ecco un semplice esempio di estensione:
public class Main {
public static void main(String[] args) {
int bigNumber = 10000000;
byte littleNumber = 16;
bigNumber = littleNumber;
System.out.println(bigNumber);
}
}
Qui assegniamo un valore byte
a una variabile int
. L'assegnazione è andata a buon fine e senza problemi: il valore memorizzato in byte
occupa meno spazio di memoria di quello che “sta” in int
. La “piccola bambola da nidificazione” (valore byte
) si adatta facilmente alla “grande matrioska” (variabile int
). Un'altra questione è quando provi a fare il contrario: inserisci un valore elevato in una variabile che non è progettata per tali dimensioni. In linea di principio, questo trucco non funzionerà con le vere bambole da nidificazione, ma in Java funzionerà, ma con sfumature. Proviamo a inserire un valore int
in una variabile short
:
public static void main(String[] args) {
int bigNumber = 10000000;
short littleNumber = 1000;
littleNumber = bigNumber;//error!
System.out.println(bigNumber);
}
Errore! Il compilatore capisce che stai cercando di fare qualcosa di non standard e inserisce una bambola matrioska grande ( int
) all'interno di una piccola ( short
). Un errore di compilazione in questo caso è un avvertimento da parte del compilatore: “ Ehi, sei sicuro di volerlo fare? “Se sei sicuro, dillo al compilatore: “ Va tutto bene, so cosa sto facendo!” Questo processo è chiamato conversione esplicita del tipo o restringimento . Per effettuare un restringimento, devi indicare esplicitamente il tipo a cui vuoi trasmettere il tuo valore. In altre parole, rispondi alla domanda del compilatore: " Bene, in quale di queste bamboline vuoi mettere questa grande bambola?" " Nel nostro caso sarà simile a questo:
public static void main(String[] args) {
int bigNumber = 10000000;
short littleNumber = 1000;
littleNumber = (short) bigNumber;
System.out.println(littleNumber);
}
Abbiamo esplicitamente indicato che vogliamo adattare il valore int
a una variabile short
e assumercene la responsabilità. Il compilatore, vedendo l'indicazione esplicita di un tipo più ristretto, esegue una conversione. Quale sarà il risultato? Output della console: -27008 Un po' inaspettato. Perché esattamente così? In realtà è semplice. Avevamo il valore originale: 10000000. Era memorizzato in una variabile int
che occupava 32 bit e in forma binaria appariva così: Scriviamo questo valore nella variabile short
, ma può memorizzare solo 16 bit! Di conseguenza, solo i primi 16 bit del nostro numero verranno spostati lì, il resto verrà scartato. Di conseguenza, la variabile short
conterrà il valore , che in forma decimale è esattamente uguale a -27008. Ecco perché il compilatore “ha chiesto conferma” sotto forma di cast esplicito a un tipo specifico. In primo luogo, mostra che ti assumi la responsabilità del risultato e, in secondo luogo, indica al compilatore quanto spazio allocare durante il cast dei tipi. Dopotutto, se nell'ultimo esempio avessimo castato int
su type byte
, e non su short
, avremmo a disposizione solo 8 bit, non 16, e il risultato sarebbe stato diverso. Per i tipi frazionari ( float
e double
), il restringimento avviene in modo diverso. Se provi a convertire un numero di questo tipo in un tipo intero, la sua parte frazionaria verrà scartata.
public static void main(String[] args) {
double d = 2.7;
long x = (int) d;
System.out.println(x);
}
Uscita console: 2
Tipo di dati car
Sai già che il tipo char viene utilizzato per visualizzare singoli caratteri.public static void main(String[] args) {
char c = '!';
char z = 'z';
char i = '8';
}
Ma ha una serie di caratteristiche che è importante comprendere. Consideriamo nuovamente la tabella con gli intervalli di valori:
Tipo primitivo | Dimensioni in memoria | Intervallo di valori |
---|---|---|
byte | 8 bit | da -128 a 127 |
corto | 16 bit | Da -32768 a 32767 |
car | 16 bit | da 0 a 65536 |
int | 32 bit | da -2147483648 a 2147483647 |
lungo | 64 bit | da -9223372036854775808 a 9223372036854775807 |
galleggiante | 32 bit | da (2 alla potenza -149) a ((2-2 alla potenza -23)*2 alla potenza 127) |
Doppio | 64 bit | da (-2 alla potenza di 63) a ((2 alla potenza di 63)-1) |
booleano | 8 (se utilizzato in array), 32 (se utilizzato in non array) | vero o falso |
char
ha un range numerico da 0 a 65536. Ma cosa significa? Dopotutto, char
questi non sono solo numeri, ma anche lettere, segni di punteggiatura... Il fatto è che i valori char
sono memorizzati in Java in formato Unicode. Abbiamo già incontrato Unicode in una delle lezioni precedenti. Probabilmente ricorderai che Unicode è uno standard di codifica dei caratteri che include caratteri provenienti da quasi tutte le lingue scritte del mondo. In altre parole, questo è un elenco di codici speciali in cui è presente un codice per quasi tutti i caratteri di qualsiasi lingua. La tabella generale Unicode è molto grande e, ovviamente, non ha bisogno di essere imparata a memoria. Eccone, ad esempio, una parte: La cosa principale è comprendere il principio di memorizzazione dei valori char
e ricordare che conoscendo il codice di un simbolo specifico, è sempre possibile inserirlo nel programma. Proviamolo con un numero casuale:
public static void main(String[] args) {
int x = 32816;
char c = (char) x ;
System.out.println(c);
}
Output della console: 耰 Questo è il formato in cui i caratteri vengono archiviati in Java char
. Ogni carattere corrisponde a un numero: un codice numerico di 16 bit o due byte. Unicode 32816 corrisponde al carattere 耰. Presta attenzione a questo momento. In questo esempio abbiamo utilizzato la variabile int
. Occupa 32 bit di memoria , mentre char
16 . Qui abbiamo scelto perché il numero di cui abbiamo bisogno, 32816, è fuori portata . Sebbene la dimensione , come short, sia di 16 bit, non ci sono numeri negativi nell'intervallo, quindi l'intervallo "positivo" è due volte più grande (65536 invece di 32767 ). Possiamo usare , purché il nostro codice rientri nell'intervallo 65536. Ma se creiamo un numero , occuperà più di 16 bit. E quando si restringono i tipi: int
short
char
char
char
short
int
int >65536
char c = (char) x;
i bit extra verranno scartati e il risultato sarà del tutto inaspettato.
Caratteristiche dell'addizione di caratteri e numeri interi
Diamo un'occhiata a questo insolito esempio:public class Main {
public static void main(String[] args) {
char c = '1';
int i = 1;
System.out.println(i+c);
}
}
Uscita console: 50 O_O Dov'è la logica? 1+1, da dove viene il 50?! Sai già che i valori char
sono archiviati in memoria come numeri compresi tra 0 e 65536, che rappresentano l'Unicode del nostro carattere. Quindi eccolo qui. Quando eseguiamo l'addizione char
, alcuni tipi interi char
vengono convertiti nel numero che corrisponde ad esso in Unicode. Quando nel nostro codice abbiamo aggiunto 1 e '1', il simbolo '1' è stato trasformato nel suo codice, che è 49 (puoi verificarlo nella tabella sopra). Pertanto, il risultato è diventato uguale a 50. Prendiamo ancora una volta il nostro vecchio amico -耰come esempio e proviamo ad sommarlo con un numero.
public static void main(String[] args) {
char c = '耰';
int x = 200;
System.out.println(c + x);
}
Output della console: 33016 Abbiamo già scoperto che corrisponde al codice 32816. E quando aggiungiamo questo numero e 200, otteniamo esattamente il nostro risultato: 33016 :) Il meccanismo di funzionamento, come puoi vedere, è abbastanza semplice.
GO TO FULL VERSION