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

Иногда возникают ситуации, когда необходимо переменной одного типа присвоить значение переменной другого типа. Например:

int i = 11;
byte b = 22;
i = b;

В Java существует два типа преобразований - автоматическое преобразование (неявное) и приведение типов (явное преобразование).

Два типа преобразования в Java фото

1. Автоматическое преобразование типов Java

Рассмотрим сначала автоматическое преобразование. Если оба типа совместимы, их преобразование будет выполнено в Java автоматически. Например, значение типа byte всегда можно присвоить переменной типа int, как это показано в предыдущем примере.

Для автоматического преобразования типа должно выполняться два условия:

  • оба типа должны быть совместимы
  • длина целевого типа должна быть больше длины исходного типа

В этом случае происходит преобразование с расширением. 

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

Схема совместимых преобразований для примитивных типов в Java фото

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

Например, тип данных int всегда достаточно велик, чтобы хранить все допустимые значения типа byte, поэтому никакие операторы явного приведения типов в данном случае не требуются. С точки зрения расширяющего преобразования числовые типы данных, в том числе целочисленные и с плавающей точкой, совместимы друг с другом. В то же время не существует автоматических преобразований числовых типов в тип char или boolean. Типы char и boolean также не совместимы друг с другом.

Стоит немного пояснить почему, к примеру тип byte не преобразуется автоматически (не явно) в тип char, хотя тип byte имеет ширину 8 бит, а char - 16, тоже самое касается и преобразования типа short в char. Это происходит потому, что byte и short знаковые типы данных, а char без знаковый. Поэтому в данном случае требуется использовать явное приведение типов, поскольку компилятору надо явно указать, что вы знаете чего хотите и как будет обрабатываться знаковый бит типов byte и short при преобразовании к типу char.

Поведение величины типа char в большинстве случаев совпадает с поведением величины целого типа, следовательно, значение типа char можно использовать везде, где требуются значения int или long. Однако напомним, что тип char не имеет знака, поэтому он ведет себя отлично от типа short, несмотря на то что диапазон обоих типов равен 16 бит.

2. Приведение типов Java

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

Чтобы выполнить преобразование двух несовместимых типов данных, нужно воспользоваться приведением типов. Приведение - это всего лишь явное преобразование типов. Общая форма приведения типов имеет следующий вид:

(целевой_тип) значение

где параметр целевой_тип обозначает тип, в который нужно преобразовать указанное значение.

Например, в следующем фрагменте кода тип int приводится к типу byte:

int i = 11;
byte b = 22;
b = (byte) i;

Рассмотрим пример преобразования значений с плавающей точкой в целые числа. В этом примере дробная часть значения с плавающей точкой просто отбрасывается (операция усечения):

double d = 3.89;
int a = (int) d; //Результат будет 3

При приведении более емкого целого типа к менее емкому старшие биты просто отбрасываются:

int i = 323;
byte b = (byte) i; //Результат будет 67

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

double d = 389889877779.89;
short s = (short) d; //Результат будет -1

3. Автоматическое продвижение типов в выражениях

Помимо операций присваивания, определенное преобразование типов может выполняться и в выражениях.

В языке Java действуют следующие правила:

  1. Если один операнд имеет тип double, другой тоже преобразуется к типу double.
  2. Иначе, если один операнд имеет тип float, другой тоже преобразуется к типу float.
  3. Иначе, если один операнд имеет тип long, другой тоже преобразуется к типу long.
  4. Иначе оба операнда преобразуются к типу int.
  5. В выражениях совмещенного присваивания (+=,-=,*=,/=) нет необходимости делать приведение. 

 Приведем пример:

При умножении переменной b1 (byte) на 2 (int) результат будет типа int. Поэтому при попытке присвоить результат в переменную b2 (byte) возникнет ошибка компиляции. Но при использовании совмещенной операции присваивания (*=), такой проблемы не возникнет:

byte b1 = 1;
byte b2 = 2 * b1; //Ошибка компиляции
int i1 = 2 * b1;
b2 *= 2;

В следующем примере тоже возникнет ошибка компиляции - несмотря на то, что складываются числа типа byte, результатом операции будет тип int, а не short.

public class IntegerDemo1 {
    public static void main(String[] args) {
        byte b1 = 50, b2 = -99;
        short k = b1 + b2; //ошибка компиляции
        System.out.println("k=" + k);
    }
}

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

public class IntegerDemo2 {
    public static void main(String[] args) {
        byte b1 = 50, b2 = -99;
        b1 += b2;
        System.out.println("b1=" + b1);
    }
}
Read also:
Comments