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
может иметь десятичные значения, у которых нет соответствующего длинного
значения. Поэтому мы получим ту же ошибку.
Точно так же присвоение двойного
числа int
вызовет ту же ошибку:
double doubleNum = 1.2;
int intNum = doubleNum;
incompatible types: possible lossy conversion from double to int
Двойные значения
могут быть слишком большими или слишком маленькими для int
, а десятичные значения будут потеряны при преобразовании. Следовательно, это потенциальное преобразование с потерями.
Также мы можем столкнуться с этой ошибкой при выполнении простого вычисления:
int fahrenheit = 100;
int celcius = (fahrenheit - 32) * 5.0 / 9.0;
Когда double
умножается на int
, мы получаем результат в виде double
. Следовательно, это также потенциальное преобразование с потерями.
Следовательно, несовместимые типы при преобразовании с потерями могут иметь разные размеры или типы (целые или десятичные числа). **
**
3. Примитивные типы данных
В Java доступно множество примитивных типов данных с соответствующими классами-оболочками .
Далее составим удобный список всех возможных преобразований с потерями в Java:
короткий
добайта
илисимвола
char
вбайт
иликороткий
int
вbyte
,short
илиchar
long
tobyte
,short
,char
илиint
плавать
вbyte
,short
,char
,int
илиlong
удвоить
вbyte
,short
,char
,int
,long
илиfloat
Обратите внимание, что короткие
и char
имеют одинаковый размер. Тем не менее, преобразование из типа short
в char
происходит с потерями, поскольку char
является беззнаковым типом данных .
4. Методы преобразования
4.1. Преобразование между примитивными типами
Самый простой способ преобразования примитивов , чтобы избежать преобразования с потерями, — это преобразование вниз; другими словами, преобразование шрифта большего размера в шрифт меньшего размера. Следовательно, это также называется сужающим примитивным преобразованием.
Например, давайте преобразуем длинное
число в короткое
, используя понижающее приведение :
long longNum = 24;
short shortNum = (short) longNum;
assertEquals(24, shortNum);
Точно так же давайте преобразуем double
в int
:
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.
Точно так же, когда smallLongNum
преобразуется в short
. Значение shortNum2
равно 32767, так как Java переходит к следующему максимальному значению short
.
Кроме того, давайте посмотрим, что произойдет, когда мы преобразуем максимальное и минимальное значения long
в int
:
long maxLong = Long.MAX_VALUE;
int minInt = (int) maxLong;
assertEquals(-1, minInt);
long minLong = Long.MIN_VALUE;
int maxInt = (int) minLong;
assertEquals(0, maxInt);
4.2. Преобразование между объектами-оболочками и примитивными типами
Чтобы напрямую преобразовать объект-оболочку в примитив, мы можем использовать различные методы в классах-оболочках, такие как intValue()
, shortValue()
и longValue()
. Это называется распаковкой
.
Например, давайте преобразуем объект Float
в long
:
Float floatNum = 17.564f;
long longNum = floatNum.longValue();
assertEquals(17, longNum);
Кроме того, если мы посмотрим на реализацию longValue
или подобных методов, мы обнаружим использование сужающего примитивного преобразования:
public long longValue() {
return (long) value;
}
Однако иногда следует избегать сужения примитивного преобразования, чтобы сохранить ценную информацию:
Double doubleNum = 15.9999;
long longNum = doubleNum.longValue();
assertEquals(15, longNum);
После преобразования значение longNum
будет равно 15. Однако значение doubleNum
равно 15,9999, что очень близко к 16.
Вместо этого мы можем использовать Math.round()
для преобразования в ближайшее целое число:
Double doubleNum = 15.9999;
long longNum = Math.round(doubleNum);
assertEquals(16, longNum);
4.3. Преобразование между объектами-оболочками
Для этого воспользуемся уже рассмотренными методами конвертации.
Сначала мы преобразуем объект-оболочку в примитивное значение, приведем его к понижению и преобразуем в другой объект-оболочку . Другими словами, мы будем выполнять методы распаковки, преобразования вниз и упаковки.
Например, давайте преобразуем объект Double
в объект Integer
:
Double doubleNum = 10.3;
double dbl = doubleNum.doubleValue(); // unboxing
int intgr = (int) dbl; // downcasting
Integer intNum = Integer.valueOf(intgr);
assertEquals(Integer.valueOf(10), intNum);
Наконец, мы используем Integer
. valueOf()
для преобразования примитивного типа int
в объект Integer
. Этот тип преобразования называется боксом
.
5. Вывод
В этой статье мы рассмотрели концепцию преобразования с потерями в Java с помощью ряда примеров. Кроме того, мы составили удобный список всех возможных преобразований с потерями.
Попутно мы определили сужающее примитивное преобразование как простой метод преобразования примитивных чисел и избежания ошибки преобразования с потерями.
В то же время мы также изучили дополнительные удобные методы числового преобразования в Java.
Реализации кода для этой статьи можно найти на GitHub .