Примитивные преобразования Java

Java Примитивные Преобразования

1. Вступление

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

  1. примитивные типы данных

  2. абстрактные типы данных.

В этой статье мы сосредоточимся на преобразованиях примитивных типов.

2. Обзор примитивов

Первое, что мы должны знать, это то, какие значения могут использоваться с примитивными типами. Есть восемь примитивных типов, которые:

  • byte - 8 бит и со знаком

  • short - 16 бит и со знаком

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

  • int - 32 бита и со знаком

  • long - 64 бита и со знаком

  • float - 32 бита и со знаком

  • double - 64 бита и со знаком

  • boolean - не числовой, может иметь только значенияtrue илиfalse

Это не предназначено, чтобы быть обширным обсуждением примитивов, и мы немного поговорим об их деталях по мере необходимости во время преобразований.

3. Расширение примитивных преобразований

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

int myInt = 127;
long myLong = myInt;

Во время расширенного преобразования меньшее примитивное значение помещается над большим контейнером, что означает, что все дополнительное пространство слева от значения заполнено нулями. Это также может быть использовано для перехода от целочисленной группы к плавающей точке:

float myFloat = myLong;
double myDouble = myLong;

Это возможно, потому что переход к более широкому примитиву не теряет никакой информации.

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

Иногда нам нужно соответствовать значению, которое больше, чем тип, используемый в объявлении переменной. Это может привести к потере информации, так как некоторые байты придется отбросить.

В этом случае мы должны явно выразить, что мы знаем о ситуации, и мы согласны с этим, используя приведение:

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

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

Такая ситуация происходит вvery specific case when we want to convert from a byte to a char. Первое преобразование - это расширениеbyte доint, а затем отint оно сужается доchar.

Пример прояснит этот момент:

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

Бинарное представление 130 одинаково для -126, разница заключается в интерпретации сигнала бита. Давайте теперь конвертируем изbyte вchar:

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

Представлениеchar является значением Unicode, но преобразование вint показало нам очень большое значение, у которого младшие 8 битов точно такие же, как -126.

Если мы снова преобразуем его вbyte, мы получим:

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

Хотя представлениеbyte то же самое, то есть -126, представлениеchar дает нам два разных символа.

6. Boxing/Unboxing Conversion

В Java у нас есть класс Wrapper для каждого примитивного типа, это умный способ предоставить программистам полезные методы обработки, без лишних затрат на то, чтобы все было в виде ссылки на тяжелый объект. Начиная с Java 1.5 была включена возможность автоматического преобразования в / из примитива в объект и обратно, что достигается простой атрибуцией:

Integer myIntegerReference = myInt;
int myOtherInt = myIntegerReference;

7. Строковые преобразования

Все примитивные типы могут быть преобразованы вString через их классы-оболочки, которые переопределяют метод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);

Единственным исключением здесь является классCharacter, потому чтоString в любом случае состоит изchars, таким образом, учитывая, что, вероятно,String состоит из одногоchar, мы можем использовать методcharAt() классаString:

char myNewChar = myString.charAt(0);

8. Цифровые акции

Для выполнения двоичной операции необходимо, чтобы оба операнда были совместимы по размеру.

Существует ряд простых правил, которые применяются:

  1. Если один из операндовdouble, другой повышается доdouble

  2. В противном случае, если один из операндов являетсяfloat, другой повышается доfloat

  3. В противном случае, если один из операндов являетсяlong, другой повышается доlong

  4. В противном случае оба считаютсяint

Давайте посмотрим на пример:

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

Оба операнда были повышены доint, и результат должен быть снова понижен доbyte.

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

Преобразование между типами - это очень распространенная задача в повседневной деятельности. There is a set of rules that govern the ways in which statically typed languages operate those conversions. Знание этих правил может сэкономить много времени при попытке выяснить, почему тот или иной код компилируется или нет.

Код, использованный в этой статье, можно найтиover on GitHub.