«1. Обзор

В этом кратком руководстве мы обсудим концепцию преобразования с потерями в Java и причину этого.

В то же время мы рассмотрим некоторые удобные методы преобразования, чтобы избежать этой ошибки.

2. Преобразование с потерями

Преобразование с потерями — это просто потеря информации при обработке данных.

В Java это соответствует возможности потери значения или точности переменной при преобразовании одного типа в другой.

Когда мы пытаемся присвоить переменную большого типа типу меньшего размера, Java выдаст ошибку, несовместимые типы: возможное преобразование с потерями при компиляции кода.

Например, давайте попробуем присвоить значение long для int:

long longNum = 10;
int intNum = longNum;

Java выдаст ошибку при компиляции этого кода:

incompatible types: possible lossy conversion from long to int

Здесь Java найдет long и int несовместимыми и приведет к ошибка преобразования с потерями. Поскольку могут быть длинные значения за пределами диапазона int от -2 147 483 648 до 2 147 483 647.

Точно так же давайте попробуем присвоить float длинному:

float floatNum = 10.12f;
long longNum = floatNum;
incompatible types: possible lossy conversion from float to long

Поскольку float может иметь десятичные значения, у которых нет соответствующего длинного значения. Поэтому мы получим ту же ошибку.

double doubleNum = 1.2;
int intNum = doubleNum;
incompatible types: possible lossy conversion from double to int

Точно так же присвоение числа типа double типу int вызовет ту же ошибку:

int fahrenheit = 100;
int celcius = (fahrenheit - 32) * 5.0 / 9.0;

Значения типа double могут быть слишком большими или слишком маленькими для типа int, а десятичные значения будут потеряны при преобразовании. Следовательно, это потенциальное преобразование с потерями.

Также мы можем столкнуться с этой ошибкой при выполнении простого вычисления:

При умножении числа double на число int мы получаем результат типа double. Следовательно, это также потенциальное преобразование с потерями.

Таким образом, несовместимые типы при преобразовании с потерями могут иметь разные размеры или типы (целые или десятичные числа).

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

    В Java доступно множество примитивных типов данных с соответствующими классами-оболочками.

Далее давайте составим удобный список всех возможных преобразований с потерями в Java:

short в byte или char char в byte или short int в byte, short или char long в byte, short, char или int float в byte , short, char, int или long double to byte, short, char, int, long или float

Обратите внимание, что короткие и char имеют одинаковый размер. Тем не менее, преобразование из типа short в char происходит с потерями, поскольку char является беззнаковым типом данных.

4. Методы преобразования

4.1. Преобразование между примитивными типами

long longNum = 24;
short shortNum = (short) longNum;
assertEquals(24, shortNum);

Самый простой способ преобразования примитивов, чтобы избежать преобразования с потерями, — это преобразование вниз; другими словами, преобразование шрифта большего размера в шрифт меньшего размера. Следовательно, это также называется сужающим примитивным преобразованием.

double doubleNum = 15.6;
int integerNum = (int) doubleNum;
assertEquals(15, integerNum);

Например, давайте преобразуем длинное число в короткое с помощью понижающего приведения:

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

long largeLongNum = 32768; 
short minShortNum = (short) largeLongNum;
assertEquals(-32768, minShortNum);

long smallLongNum = -32769;
short maxShortNum = (short) smallLongNum;
assertEquals(32767, maxShortNum);

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

Преобразуем длинные значения вне диапазона коротких:

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

Другими словами, когда Java достигает максимального значения мелкого типа при преобразовании из крупноразмерного типа, следующее число является наименьшим значением мелкоразмерного типа и наоборот.

Давайте разберемся с этим на примерах. Когда largeLongNum со значением 32768 преобразуется в short, значение shortNum1 равно -32768. Поскольку максимальное значение short равно 32767, поэтому Java выбирает следующее минимальное значение short.

long maxLong = Long.MAX_VALUE; 
int minInt = (int) maxLong;
assertEquals(-1, minInt);

long minLong = Long.MIN_VALUE;
int maxInt = (int) minLong;
assertEquals(0, maxInt);

Аналогично, когда smallLongNum конвертируется в short. Значение shortNum2 равно 32767, так как Java переходит к следующему максимальному значению шорта.

Кроме того, давайте посмотрим, что происходит, когда мы конвертируем максимальное и минимальное значения long в int:

4.2. Преобразование между объектами-оболочками и примитивными типами

Float floatNum = 17.564f;
long longNum = floatNum.longValue();
assertEquals(17, longNum);

Чтобы напрямую преобразовать объект-оболочку в примитив, мы можем использовать различные методы в классах-оболочках, такие как intValue(), shortValue() и longValue(). Это называется распаковкой.

public long longValue() {
    return (long) value;
}

Например, давайте преобразуем объект типа Float в тип long:

Double doubleNum = 15.9999;
long longNum = doubleNum.longValue();
assertEquals(15, longNum);

«

«Кроме того, если мы посмотрим на реализацию longValue или подобных методов, мы обнаружим использование сужающего примитивного преобразования:

Double doubleNum = 15.9999;
long longNum = Math.round(doubleNum);

assertEquals(16, longNum);

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

После преобразования значение longNum будет равно 15. Однако значение doubleNum равно 15,9999, что очень близко к 16.

Вместо этого мы можем использовать Math.round() для преобразования в ближайшее целое число: ~~ ~

4.3. Преобразование между объектами-оболочками

Double doubleNum = 10.3;
double dbl = doubleNum.doubleValue(); // unboxing
int intgr = (int) dbl; // downcasting
Integer intNum = Integer.valueOf(intgr);
assertEquals(Integer.valueOf(10), intNum);

Для этого воспользуемся уже обсуждавшимися методами преобразования.

Сначала мы преобразуем объект-оболочку в примитивное значение, приведем его к понижению и преобразуем в другой объект-оболочку. Другими словами, мы будем выполнять методы распаковки, преобразования вниз и упаковки.

Например, давайте преобразуем объект Double в объект Integer:

Наконец, мы используем Integer.valueOf() для преобразования примитивного типа int в объект Integer. Этот тип преобразования называется боксом.

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

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