1. Tipare

Typecasting în Java

Variabilele de tipuri primitive (cu excepția tipului boolean) sunt folosite pentru a stoca diferite tipuri de numere. Deși tipurile de variabile nu s-au schimbat niciodată, există un loc în care puteți converti de la un tip la altul. Și acel loc este o misiune .

Variabilele de diferite tipuri pot fi alocate între ele. Când faceți acest lucru, valoarea unei variabile de un tip este convertită într-o valoare de alt tip și atribuită celei de-a doua variabile. În acest sens, putem identifica două tipuri de conversie de tip: lărgire și îngustare.

Lărgirea este ca și cum ați muta o valoare de la un coș mic la unul mare: această operație este fără sudură și nedureroasă. Îngustarea are loc atunci când mutați o valoare dintr-un coș mare într-unul mic: s-ar putea să nu fie suficient spațiu și va trebui să aruncați ceva.

Iată tipurile, sortate după dimensiunea coșului:

Typecasting în Java 2


2. Conversii de tip lărgire

Este adesea necesar să atribuiți o variabilă de un tip numeric unei variabile de alt tip numeric. Cum faci asta?

Java are 4 tipuri de numere întregi:

Tip mărimea
byte 1 byte
short 2 bytes
int 4 bytes
long 8 bytes

Variabilele stocate în coșuri mai mici pot fi întotdeauna atribuite variabilelor stocate în coșuri mai mari.

int, shortiar bytevariabilele pot fi atribuite cu ușurință longvariabilelor. shortiar bytevariabilele pot fi atribuite intvariabilelor. Și bytevariabilele pot fi atribuite shortvariabilelor.

Exemple:

Cod Descriere
byte a = 5;
short b = a;
int c = a + b;
long d = c * c;
Acest cod se va compila foarte bine.

O astfel de conversie, de la un tip mai mic la unul mai mare, se numește conversie de tip lărgire .

Dar numerele reale?

Cu ei, totul este la fel - dimensiunea contează:

Tip mărimea
float 4 bytes
double 8 bytes

floatvariabilele pot fi alocate doublevariabilelor fără probleme. Dar lucrurile sunt mai interesante cu tipurile întregi.

Puteți aloca orice variabilă întreagă unei floatvariabile. Chiar și longtipul, care are o lungime de 8 octeți. Și puteți aloca orice doriți - orice variabilă sau floatvariabilă întreagă - unei doublevariabile:

Cod Notă
long a = 1234567890;
float b = a;
double c = a;

b == 1.23456794E9
c == 1.23456789E9

Rețineți că conversia la un tip real poate duce la pierderea preciziei din cauza lipsei de cifre semnificative suficiente.

La conversia de la numere întregi la numere în virgulă mobilă, părțile de ordin inferior ale numerelor pot fi eliminate. Dar, deoarece se înțelege că numerele fracționale stochează valori aproximative, astfel de operațiuni de atribuire sunt permise.


3. Îngustarea conversiilor de tip

Dar celelalte posibilități? Ce se întâmplă dacă trebuie să atribui o longvaloare unei intvariabile?

Imaginați-vă o variabilă ca un coș. Avem coșuri de diferite dimensiuni: 1, 2, 4 și 8 octeți. Nu este o problemă să transferi merele dintr-un coș mai mic într-unul mai mare. Dar atunci când treceți de la un coș mai mare la unul mai mic, unele dintre mere se pot pierde.

Această transformare - de la un tip mai mare la un tip mai mic - se numește conversie de tip îngustare . Când se efectuează o operație de atribuire ca aceasta, o parte dintr-un număr poate pur și simplu să nu se încadreze în noua variabilă și, prin urmare, poate fi aruncată.

Când restrângem un tip, trebuie să spunem în mod explicit compilatorului că nu facem o greșeală, că aruncăm în mod deliberat o parte din număr. Operatorul typecast este utilizat pentru aceasta. Este un nume de tip între paranteze .

În astfel de situații, compilatorul Java solicită programatorului să specifice operatorul typecast. În general, arată astfel:

(type) expression

Exemple:

Cod Descriere
long a = 1;
int b = (int) a;
short c = (short) b;
byte d = (byte) c;
De fiecare dată operatorul typecast trebuie indicat în mod explicit

Aici aeste egal cu 1, și poate că operatorul typecast pare exagerat. Dar dacă ar afi mai mare?

Cod Descriere
long a = 1000000;
int b = (int) a;
short c = (short) b;
byte d = (byte) c;
a == 1000000
b == 1000000
c == 16960
d == 64

Un milion se potrivește perfect într-un longși într-un int. Dar atunci când se atribuie un milion unei shortvariabile, primii doi octeți sunt eliminați și doar ultimii doi octeți sunt reținuți. Și când se atribuie unui byte, singurul lucru care rămâne este ultimul octet.

Cum sunt aranjate numerele în memorie:

Tip Notație binară Notație zecimală
int 0b 00000000 00001111 01000010 01000000 1000000
short 0b 01000010 01000000 16.960
byte 0b 01000000 64

chartip

A char, ca și a short, ocupă doi octeți, dar pentru a converti unul în altul, trebuie întotdeauna să utilizați un operator de tipar. Problema aici este că shorttipul este semnat și poate conține valori de la -32,768până la +32,767, dar chartipul este nesemnat și poate conține valori de la 0până la 65,535.

Numerele negative nu pot fi stocate într-un char, dar pot fi stocate într-un short. Și a shortnu poate stoca numere mai mari decât 32,767, dar astfel de numere pot fi stocate într-un char.


4. Tipul unei expresii

Ce se întâmplă dacă în aceeași expresie sunt folosite variabile de diferite tipuri? În mod logic, înțelegem că mai întâi trebuie convertite într-un tip comun. Dar care?

La cel mai mare, desigur.

Java se convertește întotdeauna la tipul mai mare. În linii mari, unul de tip este mai întâi lărgit și abia apoi operația se realizează folosind valori de același tip.

Dacă an intși a longsunt implicați într-o expresie, valoarea lui intva fi convertită în a longși numai atunci operația va continua:

Cod Descriere
int a = 1;
long b = 2;
long c = a + b;
ava fi lărgit la a longși apoi va avea loc adăugarea.

Numere în virgulă mobilă

Dacă într-o expresie sunt implicate un număr întreg și un număr în virgulă mobilă ( floatsau double), întregul va fi convertit într-un număr în virgulă mobilă ( floatsau double) și numai atunci operația va fi efectuată.

Dacă operația implică a floatși a double, atunci floatva fi convertit în a double. Ceea ce de fapt este de așteptat.

Surprinde

Tipurile byte, short, și charsunt întotdeauna convertite în intcând interacționează unul cu celălalt. Există un motiv bun pentru care inttipul este considerat tipul întreg standard.

Dacă înmulțiți a bytecu a short, obțineți un int. Dacă înmulțiți a bytecu a byte, obțineți un int. Chiar dacă adăugați a byteși a byte, obțineți un int.

Există mai multe motive pentru aceasta. Exemple:

Cod Descriere
byte a = 110;
byte b = 120;
byte c = a * b;  // Error
110 * 120este 13,200, care este puțin mai mare decât valoarea maximă a bytetipului:127
byte a = 110;
byte b = 120;
byte c = a + b; // Error
110 + 120este 230, care este, de asemenea, puțin mai mare decât valoarea maximă a bytetipului:127

În general, atunci când înmulțim un număr de 8 biți (1 octet) cu un număr de 8 biți (1 octet), obținem un număr care ocupă biți de 16 biți (2 octeți)

Ca rezultat, toate operațiile cu tipuri întregi care sunt mai mici decât intsunt întotdeauna convertite imediat în ints. Și asta înseamnă că, dacă doriți să stocați rezultatul calculului într-o variabilă de tip mai mică decât un int, atunci va trebui întotdeauna să specificați în mod explicit operatorul typecast.

Exemple:

Cod Descriere
byte a = 110;
byte b = 120;
byte c = (byte) (a * b);
Expresia byte * byteva fi anint
byte a = 110;
byte b = 120;
byte c = (byte) (a + b);
Expresia byte + byteva fi anint
byte a = 1;
byte b = (byte) (a + 1);
Expresia byte + intva fi o int
Cea literală este o int.

5. O nuanță importantă

Operatorul typecast are o prioritate destul de mare.

Aceasta înseamnă că, dacă o expresie conține, de exemplu, adăugare și un operator de tipare, tipare va fi efectuată înainte de adăugare.

Exemplu:

Cod Descriere
byte a = 1;
byte b = 2;
byte c = (byte) a * b;
Operatorul typecast va fi aplicat numai variabilei a, care este deja un byte. Acest cod nu se va compila.
byte a = 1;
byte b = 2;
byte c = (byte) (a * b);
Acesta este modul corect.

Dacă doriți să convertiți întreaga expresie într-un anumit tip, și nu doar o componentă a expresiei, atunci includeți întreaga expresie în paranteze și puneți operatorul typecast în față.