Bună! Pe măsură ce ați progresat prin CodeGym, ați întâlnit tipuri primitive de multe ori. Iată o scurtă listă a ceea ce știm despre ei:
- Nu sunt obiecte și reprezintă o valoare stocată în memorie
- Există mai multe feluri
- Numere întregi: octet , scurt , int , lung
- Numere în virgulă mobilă (fracționale): flotant și dublu
- Valori logice: boolean
- Valori simbolice (pentru reprezentarea literelor și cifrelor): char
-
Fiecare tip are propriul său interval de valori:
Tipul primitiv |
Dimensiunea în memorie |
Interval de valori |
octet |
8 biți |
-128 la 127 |
mic de statura |
16 biți |
-32768 până la 32767 |
char |
16 biți |
0 la 65536 |
int |
32 de biți |
-2147483648 până la 2147483647 |
lung |
64 de biți |
-9223372036854775808 până la 9223372036854775807 |
pluti |
32 de biți |
(2 la puterea lui -149) la ((2 - (2 la puterea lui -23)) * 2 la puterea lui 127) |
dubla |
64 de biți |
(-2 la puterea lui 63) la ((2 la puterea lui 63) - 1) |
boolean |
8 (când este folosit în matrice), 32 (dacă nu este utilizat în matrice) |
adevărat sau fals |
Dar, pe lângă faptul că au valori diferite, diferă și prin cât spațiu ocupă în memorie. Un
int ia mai mult de un octet. Și un
lung este mai mare decât un scurt. Cantitatea de memorie ocupată de primitivi poate fi comparată cu păpușile rusești:
![Lărgirea și îngustarea tipurilor primitive - 2]()
fiecare păpușă are spațiu disponibil în interior. Cu cât păpușa de cuibărit este mai mare, cu atât este mai mult spațiu. O păpușă mare (
lungă ) va găzdui cu ușurință un
int mai mic . Se potrivește ușor și nu trebuie să faci nimic altceva. În Java, atunci când lucrați cu primitive, aceasta se numește conversie implicită. Sau altfel spus, se numește lărgire.
Extindere în Java
Iată un exemplu simplu de conversie în creștere:
public class Main {
public static void main(String[] args) {
int bigNumber = 10000000;
byte littleNumber = 16;
bigNumber = littleNumber;
System.out.println(bigNumber);
}
}
Aici atribuim o valoare de octet unei variabile
int . Atribuirea reușește fără probleme: valoarea stocată într-un octet ocupă mai puțină memorie decât ceea ce poate găzdui un
int . Mica păpușă de cuibărit (valoarea octetului) se potrivește cu ușurință în interiorul păpușii de cuib mare ( variabilă
int ). Este o altă problemă dacă încerci să faci invers, adică să pui o valoare mare într-o variabilă al cărei interval nu poate găzdui un tip de date atât de mare. Cu păpușile reale, numărul pur și simplu nu s-ar potrivi. Cu Java, se poate, dar cu nuanțe. Să încercăm să punem un
int într-o variabilă
scurtă :
public static void main(String[] args) {
int bigNumber = 10000000;
short littleNumber = 1000;
littleNumber = bigNumber;// Error!
System.out.println(bigNumber);
}
Eroare! Compilatorul înțelege că încercați să faceți ceva anormal prin împingerea unei păpuși de cuib mare (
int ) în una mică (
scurtă ). În acest caz, eroarea de compilare este un avertisment din partea compilatorului: „Hei, ești
absolut sigur că vrei să faci asta?” Dacă ești sigur, atunci îi spui compilatorului:
"Totul este în regulă. Știu ce fac!" Acest proces se numește conversie explicită de tip sau îngustare.
Îngustarea în Java
Pentru a efectua o conversie de restrângere, trebuie să indicați în mod explicit tipul în care doriți să vă convertiți valoarea. Cu alte cuvinte, trebuie să răspunzi la întrebarea compilatorului:
„Ei bine, în care dintre aceste păpuși mici de cuibărit vrei să pui această păpușă mare de cuib?” În cazul nostru, arată astfel:
public static void main(String[] args) {
int bigNumber = 10000000;
short littleNumber = 1000;
littleNumber = (short) bigNumber;
System.out.println(littleNumber);
}
Indicăm în mod explicit că vrem să punem un
int într-o variabilă
scurtă și că ne vom asuma responsabilitatea. Văzând că un tip mai restrâns a fost indicat în mod explicit, compilatorul efectuează conversia. Care este rezultatul? Ieșire din consolă:
-27008 A fost puțin neașteptat. De ce exact am primit asta? De fapt, totul este foarte simplu. Inițial, valoarea era 10000000 A fost stocată într-o variabilă
int , care ocupă 32 de biți. Aceasta este reprezentarea sa binară:
Scriem această valoare într-o variabilă
scurtă , care poate stoca doar 16 biți! În consecință, doar primii 16 biți ai numărului nostru vor fi mutați acolo. Restul va fi aruncat. Ca rezultat, variabila scurtă primește următoarea valoare
care în formă zecimală este egală cu -27008 De aceea, compilatorul vă cere să „confirmați” indicând o conversie explicită de restrângere la un anumit tip. În primul rând, aceasta arată că îți asumi responsabilitatea pentru rezultat. Și în al doilea rând, îi spune compilatorului cât spațiu să aloce atunci când are loc conversia. La urma urmei, în ultimul exemplu, dacă am atribui o valoare int unei variabile octet mai degrabă decât unui
short , atunci am avea doar 8 biți la dispoziție, nu 16, iar rezultatul ar fi diferit. Tipurile fracționale (
float și
double ) au propriul lor proces de îngustare a conversiilor. Dacă încercați să turnați un număr fracțional într-un tip întreg, partea fracțională va fi eliminată.
public static void main(String[] args) {
double d = 2.7;
long x = (int) d;
System.out.println(x);
}
Ieșire consolă:
2
char
Știți deja că
char este folosit pentru a afișa caractere individuale.
public static void main(String[] args) {
char c = '!';
char z = 'z';
char i = '8';
}
Dar acest tip de date are mai multe caracteristici care sunt importante de înțeles. Să ne uităm din nou la tabelul intervalelor de valori:
Tipul primitiv |
Dimensiunea în memorie |
Interval de valori |
octet |
8 biți |
-128 la 127 |
mic de statura |
16 biți |
-32768 până la 32767 |
char |
16 biți |
0 la 65536 |
int |
32 de biți |
-2147483648 până la 2147483647 |
lung |
64 de biți |
-9223372036854775808 până la 9223372036854775807 |
pluti |
32 de biți |
(2 la puterea lui -149) la ((2 - (2 la puterea lui -23)) * 2 la puterea lui 127) |
dubla |
64 de biți |
(-2 la puterea lui 63) la ((2 la puterea lui 63) - 1) |
boolean |
8 (când este folosit în matrice), 32 (dacă nu este utilizat în matrice) |
adevărat sau fals |
Intervalul de la 0 la 65536 este indicat pentru tipul
de caractere . Dar ce înseamnă asta? La urma urmei, un
caracter nu reprezintă doar numere, ci și litere, semne de punctuație... Chestia este că în Java valorile
de caractere sunt stocate în format Unicode. Am întâlnit deja Unicode într-una dintre lecțiile anterioare. Probabil vă amintiți că Unicode este un standard de codificare a caracterelor care include simbolurile aproape tuturor limbilor scrise ale lumii. Cu alte cuvinte, este o listă de coduri speciale care reprezintă aproape fiecare caracter în orice limbă. Întregul tabel Unicode este foarte mare și, desigur, nu este nevoie să-l înveți pe de rost. Iată o mică parte din el:
![Lărgirea și îngustarea tipurilor primitive - 5]()
Principalul lucru este să înțelegeți cum sunt stocate caracterele și să vă amintiți că, dacă cunoașteți codul pentru un anumit caracter, puteți oricând să produceți acel caracter în programul dvs. Să încercăm cu un număr aleator:
public static void main(String[] args) {
int x = 32816;
char c = (char) x ;
System.out.println(c);
}
Ieșire din consolă: 耰 Acesta este formatul folosit pentru stocarea
caracterelor în Java. Fiecare simbol corespunde unui număr: un cod numeric de 16 biți (doi octeți). În Unicode, 32816 corespunde caracterului chinezesc 耰. Luați notă de următorul punct. În acest exemplu, am folosit o variabilă
int . Ocupă 32 de biți în memorie, în timp ce un
caracter ocupă 16. Aici am ales un
int , deoarece numărul nostru (32816) nu va încadra într-un
scurt . Deși dimensiunea unui
caracter (la fel ca un
scurt ) este de 16 biți, nu există numere negative în intervalul
de caractere , deci partea „pozitivă” a
caracteruluiintervalul este de două ori mai mare (65536 în loc de 32767 pentru tipul
scurt ). Putem folosi un
int atâta timp cât codul nostru rămâne sub 65536. Dar dacă creați o valoare
int mai mare decât 65536, atunci aceasta va ocupa mai mult de 16 biți. Și acest lucru va avea ca rezultat o conversie îngustă
char c = (char) x;
biții suplimentari vor fi aruncați (așa cum am discutat mai sus) și rezultatul va fi destul de neașteptat.
Caracteristici speciale de adăugare de caractere și numere întregi
Să ne uităm la un exemplu neobișnuit:
public class Main {
public static void main(String[] args) {
char c = '1';
int i = 1;
System.out.println(i + c);
}
}
Ieșire consolă:
50 O_О Cum are sens? 1+1. De unde au venit cei 50?! Știți deja că
char
valorile sunt stocate în memorie ca numere în intervalul de la 0 la 65536 și că aceste numere sunt o reprezentare Unicode a unui caracter.
![Lărgirea și îngustarea tipurilor primitive - 6]()
Când adăugăm un
caracter și un tip de număr întreg,
caracterul este convertit în numărul Unicode corespunzător. În codul nostru, când am adăugat 1 și „1”, simbolul „1” a fost convertit în propriul cod, care este 49 (puteți verifica acest lucru în tabelul de mai sus). Prin urmare, rezultatul este 50. Să luăm din nou vechiul nostru prieten 耰 ca exemplu și să încercăm să-l adăugăm la un număr.
public static void main(String[] args) {
char c = '耰';
int x = 200;
System.out.println(c + x);
}
Ieșire din consolă:
33016 Am descoperit deja că 耰 corespunde cu 32816. Și când adunăm acest număr și 200, obținem rezultatul nostru: 33016. :) După cum puteți vedea, algoritmul de aici este destul de simplu, dar nu ar trebui să-l uitați .
GO TO FULL VERSION