1. Преобразуване на типове

Преобразуване на типове в Java

Променливите от примитивни типове (с изключение на booleanтипа) се използват за съхраняване на различни видове числа. Въпреки че типовете променливи никога не са се променяли, има място, където можете да конвертирате от един тип в друг. И това място е наmeaning .

Променливи от различни типове могат да бъдат присвоени една на друга. Когато направите това, стойността на променлива от един тип се преобразува в стойност от друг тип и се присвоява на втората променлива. В това отношение можем да идентифицираме два вида преобразуване на типове: разширяване и стесняване.

Разширяването е като преместване на стойност от малка кошница в голяма: тази операция е безпроблемна и безболезнена. Стесняването се случва, когато преместите стойност от голяма кошница в малка: може да няма достатъчно място и ще трябва да изхвърлите нещо.

Ето видовете, сортирани по размер на кошницата:

Преобразуване на типове в Java 2


2. Разширяване на типовите преобразувания

Често е необходимо променлива от един числов тип да се присвои на променлива от друг числов тип. Как правиш това?

Java има 4 цели числа:

Тип Размер
byte 1 byte
short 2 bytes
int 4 bytes
long 8 bytes

Променливите, съхранявани в по-малки кошници, винаги могат да бъдат присвоени на променливи, съхранявани в по-големи кошници.

int, shortа byteпроменливите могат лесно да бъдат присвоени на longпроменливи. shortи byteпроменливите могат да бъдат присвоени на intпроменливи. И byteпроменливите могат да бъдат присвоени на shortпроменливи.

Примери:

Код Описание
byte a = 5;
short b = a;
int c = a + b;
long d = c * c;
Този code ще се компorра добре.

Такова преобразуване от по-малък към по-голям тип се нарича преобразуване на разширяващ се тип.

Какво ще кажете за реалните числа?

При тях всичко е същото - размерът има meaning:

Тип Размер
float 4 bytes
double 8 bytes

floatпроменливите могат да бъдат присвоени на doubleпроменливи без ниHowви проблеми. Но нещата са по-интересни с целочислените типове.

Можете да присвоите всяка променлива с цяло число към floatпроменлива. Дори longтипът, който е дълъг 8 byteа. И можете да присвоите Howвото искате - всяка променлива с цяло число or floatпроменлива - към doubleпроменлива:

Код Забележка
long a = 1234567890;
float b = a;
double c = a;

b == 1.23456794E9
c == 1.23456789E9

Обърнете внимание, че преобразуването в реален тип може да доведе до загуба на точност поради липсата на достатъчно значими цифри.

При преобразуване от цели числа към числа с плаваща запетая, частите от по-нисък ред на числата могат да бъдат изхвърлени. Но тъй като се разбира, че дробните числа съхраняват приблизителни стойности, такива операции за присвояване са разрешени.


3. Стесняващи преобразувания на типове

Какво ще кажете за другите възможности? Ами ако трябва да присвоите longстойност на intпроменлива?

Представете си променлива като кошница. Разполагаме с кошници с различни размери: 1, 2, 4 и 8 byteа. Не е проблем да прехвърлите ябълки от по-малка кошница в по-голяма. Но при преместване от по-голяма кошница в по-малка, някои от ябълките може да се загубят.

Тази трансформация — от по-голям тип към по-малък тип — се нарича преобразуване на стесняващ тип . Когато извършвате операция за присвояване като тази, част от число може просто да не се побере в новата променлива и следователно може да бъде отхвърлена.

Когато стесняваме тип, трябва изрично да кажем на компилатора, че не правим грешка, че нарочно изхвърляме част от числото. За това се използва операторът typecast. Това е име на тип в скоби .

В такива ситуации компилаторът на Java изисква от програмиста да посочи оператора за преобразуване на типа. В общи линии изглежда така:

(type) expression

Примери:

Код Описание
long a = 1;
int b = (int) a;
short c = (short) b;
byte d = (byte) c;
Всеки път операторът за придаване на типа трябва да бъде посочен изрично

Тук aе равно на 1и може би операторът typecast изглежда пресилен. Но Howво, ако aбяха по-големи?

Код Описание
long a = 1000000;
int b = (int) a;
short c = (short) b;
byte d = (byte) c;
a == 1000000
b == 1000000
c == 16960
d == 64

Един мorон се вписва перфектно в a longи в int. Но когато присвоите един мorон на shortпроменлива, първите два byteа се изхвърлят и само последните два byteа се запазват. И когато се присвоява на byte, единственото нещо, което остава, е последният byte.

Как се подреждат числата в паметта:

Тип Двоичен запис Десетичен запис
int 0b 00000000 00001111 01000010 01000000 1000000
short 0b 01000010 01000000 16.960
byte 0b 01000000 64

charТип

A char, подобно на a short, заема два byteа, но за да преобразувате един в друг, винаги трябва да използвате оператор за typecast. Проблемът тук е, че shortтипът е със знак и може да съдържа стойности от -32,768до +32,767, но charтипът е без знак и може да съдържа стойности от 0до 65,535.

Отрицателните числа не могат да се съхраняват в char, но могат да се съхраняват в short. И shortне може да съхранява числа, по-големи от 32,767, но такива числа могат да се съхраняват в char.


4. Вид на израза

Какво става, ако променливи от различни типове се използват в един и същи израз? Логично разбираме, че те първо трябва да бъдат преобразувани в общ тип. Но кое?

Към по-голямата, разбира се.

Java винаги преобразува в по-големия тип. Грубо казано, първо се разширява единият тип и едва след това се извършва операцията със стойности от същия тип.

Ако an intи a longса включени в израз, стойността на intще бъде преобразувана в a longи едва тогава операцията ще продължи:

Код Описание
int a = 1;
long b = 2;
long c = a + b;
aще бъде разширен до a longи след това ще се извърши добавянето.

Числа с плаваща запетая

Ако цяло число и число с плаваща запетая ( floator double) са включени в израз, цялото число ще бъде преобразувано в число с плаваща запетая ( floator double) и едва тогава ще бъде изпълнена операцията.

Ако операцията включва a floatи a double, тогава floatще се преобразува в a double. Което всъщност се очаква.

Изненада

Типовете byte, shortи charвинаги се преобразуват в int, когато взаимодействат един с друг. Има основателна причина, поради която intтипът се счита за standardн целочислен тип.

Ако умножите a byteпо a short, ще получите a int. Ако умножите a byteпо a byte, ще получите a int. Дори ако добавите a byteи a byte, получавате a int.

Причините за това са няколко. Примери:

Код Описание
byte a = 110;
byte b = 120;
byte c = a * b;  // Error
110 * 120е 13,200, което е малко по-голямо от максималната стойност на byteтипа:127
byte a = 110;
byte b = 120;
byte c = a + b; // Error
110 + 120е 230, което също е малко по-голямо от максималната стойност на byteтипа:127

Като цяло, когато умножаваме 8-битово (1 byte) число с 8-битово (1 byte) число, получаваме число, което заема 16-битови бита (2 byteа)

В резултат на това всички операции с цели числа, които са по-малки от intвинаги незабавно се преобразуват в ints. И това означава, че ако искате да съхраните резултата от изчислението в променлива от тип, който е по-малък от int, тогава винаги ще трябва изрично да посочите оператора за преобразуване на типа.

Примери:

Код Описание
byte a = 110;
byte b = 120;
byte c = (byte) (a * b);
Изразът byte * byteще бъде anint
byte a = 110;
byte b = 120;
byte c = (byte) (a + b);
Изразът byte + byteще бъде anint
byte a = 1;
byte b = (byte) (a + 1);
Изразът byte + intще бъде int
Буквалният е int.

5. Важен нюанс

Операторът typecast има доста висок приоритет.

Това означава, че ако даден израз съдържа, например, добавяне и оператор за привеждане на типа, привеждането на типа ще бъде извършено преди добавянето.

Пример:

Код Описание
byte a = 1;
byte b = 2;
byte c = (byte) a * b;
Операторът за typecast ще бъде приложен само към aпроменливата, която вече е byte. Този code няма да се компorра.
byte a = 1;
byte b = 2;
byte c = (byte) (a * b);
Това е правилният начин.

Ако искате да преобразувате целия израз в конкретен тип, а не само един компонент на израза, увийте целия израз в скоби и поставете оператора за преобразуване на типа отпред.