Java примитивни конверсии

1. Въведение

Java е типизиран език, което означава, че използва концепцията за типове. Има две отделни групи от типове:

  1. примитивни типове данни
  2. абстрактни типове данни.

В тази статия ще се съсредоточим върху преобразуванията на примитивни типове.

2. Преглед на примитивите

Първото нещо, което трябва да знаем, е какъв вид стойности могат да се използват с примитивни типове. Има осем примитивни типа, които са:

  • байт - 8 бита и подписан

  • къси - 16 бита и подписани

  • char - 16 бита и без знак, така че да може да представлява Unicode символи

  • int - 32 бита и подписан

  • дълго - 64 бита и подписано

  • float - 32 бита и подписан

  • двойно - 64 бита и подписано

  • boolean - не е числово, може да има само истински или фалшиви стойности

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

3. Разширяване на примитивните конверсии

Когато трябва да конвертираме от примитив, който е по-прост или по-малък от типа на дестинацията, не е нужно да използваме специални обозначения за това:

int myInt = 127; long myLong = myInt;

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

float myFloat = myLong; double myDouble = myLong;

Това е възможно, тъй като преминаването към по-широк примитив не губи никаква информация.

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

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

В този случай трябва изрично да изразим, че сме наясно със ситуацията и сме съгласни с това, като използваме гласове:

int myInt = (int) myDouble; byte myByte = (byte) myInt;

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

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

Един пример ще изясни този момент:

byte myLargeValueByte = (byte) 130; //0b10000010 -126

Двоичното представяне на 130 е същото за -126, разликата е интерпретацията на бита на сигнала. Нека сега конвертираме от байт в char :

char myLargeValueChar = (char) myLargeValueByte; //0b11111111 10000010 unsigned value int myLargeValueInt = myLargeValueChar; //0b11111111 10000010 65410

Представянето на char е Unicode стойност, но преобразуването в int ни показа много голяма стойност, която има по-ниските 8 бита абсолютно същите като -126.

Ако го преобразуваме отново в байт , получаваме:

byte myOtherByte = (byte) myLargeValueInt; //0b10000010 -126

Оригиналната стойност, която използвахме. Ако целият код започва с char, стойностите ще бъдат различни:

char myLargeValueChar2 = 130; //This is an int not a byte! //0b 00000000 10000010 unsigned value int myLargeValueInt2 = myLargeValueChar2; //0b00000000 10000010 130 byte myOtherByte2 = (byte) myLargeValueInt2; //0b10000010 -126

Въпреки че байт представителството е същото, което е -126, в знак представителството ни дава два различни знаци.

6. Преобразуване на бокс / дебокс

В Java имаме клас Wrapper за всеки примитивен тип, това е интелигентен начин да предоставим на програмистите полезни методи за обработка, без да се налага всичко да има като тежка препратка към обект. От Java 1.5 беше включена възможността за автоматично преобразуване в / от примитив в обект и обратно и това беше постигнато чрез просто приписване:

Integer myIntegerReference = myInt; int myOtherInt = myIntegerReference;

7. Преобразувания на низове

Всички примитивни типове могат да бъдат преобразувани в String чрез техните класове Wrapper, които заменят метода toString () :

String myString = myIntegerReference.toString();

Ако трябва да се върнем към примитивен тип, трябва да използваме метод за синтактичен анализ, дефиниран от съответния клас Wrapper:

byte myNewByte = Byte.parseByte(myString); short myNewShort = Short.parseShort(myString); int myNewInt = Integer.parseInt(myString); long myNewLong = Long.parseLong(myString); float myNewFloat = Float.parseFloat(myString); double myNewDouble = Double.parseDouble(myString); 
boolean myNewBoolean = Boolean.parseBoolean(myString);

The only exception here is the Character Class because a String is made of chars anyway, this way, considering that probably the String is made of a single char, we can use the charAt() method of the String class:

char myNewChar = myString.charAt(0);

8. Numeric Promotions

To execute a binary operation, it is necessary that both operands are compatible in terms of size.

There is a set of simple rules that apply:

  1. If one of the operands is a double, the other is promoted to double
  2. Otherwise, if one of the operands is a float, the other is promoted to float
  3. В противен случай, ако единият от операндите е дълъг , другият се повишава до дълъг
  4. В противен случай и двете се считат за int

Да видим пример:

byte op1 = 4; byte op2 = 5; byte myResultingByte = (byte) (op1 + op2);

И двата операнда бяха повишени до int и резултатът отново трябва да бъде понижен до байт .

9. Заключение

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

Кодът, използван в тази статия, може да бъде намерен в GitHub.