Очевидно, что следующие четыре вида приведений легко представляется в виде таблицы 7.1.
Табл. 7.1. Виды приведений.
Что все это означает? Начнем по порядку. Для простых типов расширение означает, что осуществляется переход от менее емкого типа к более емкому, например, от типа byte (длина 1 байт) к типу int (длина 4 байта). Такие преобразования безопасны в том смысле, что новый тип всегда гарантированно вмещает в себя все данные, которые хранились в старом типе, и таким образом не происходит потери данных. Именно поэтому компилятор осуществляет его сам, незаметно для разработчика:
byte b=3; int a=b;
В последней строке значение переменной b типа byte будет преобразовано к типу переменной а (то есть, int) автоматически, никаких специальных действий для этого предпринимать не нужно.
Следующие 19 преобразований являются расширяющими:
• от byte к short, int, long, float, double
• от short к Int, long, float, double
• от char к int, long, float, double
• от int к long, float, double
• от long к float, double
• от float к double
Обратите внимание, что нельзя провести преобразование к типу char от типов меньшей или равной длины (byte, short), или, наоборот, к short от char без потери данных. Это связано с тем, что char, в отличие от остальных целочисленных типов, является беззнаковым.
Тем не менее, следует помнить, что даже при расширении данные все-таки могут быть в особых случаях искажены. Они уже рассматривались в предыдущей лекции, это приведение значений Intк типу float и приведение значений типа long к типу float или double. Хотя эти дробные типы вмешают гораздо большие числа, чем соответствующие целые, но у них меньше значащих разрядов.
Повторим этот пример:
longa=111111111111L; float f = а; а = (long) f; print(a);
Результатом будет:
Обратное преобразование — сужение — означает, что переход осуществляется от более емкого типа к менее емкому. При таком преобразовали, есть риск потерять данные. Например, если число типа int было больше 127, то при приведении его к byte значения битов старше восьмого будут потеряны. В Java такое преобразование должно совершаться явным образом, т.е. программист в коде должен явно указать, что он намеревается осуществить такое преобразование и готов потерять данные.
Следующие 23 преобразования являются сужающими:
• от byte к char
• от short к byte, char
• от char к byte, short
• от int к byte, short, char
• от long к byte, short, char, Int
• от float к byte, short, char, Int, long
• от double к byte, short, char, Int, long, float
При сужении целочисленного типа к более узкому целочисленному все старшие биты, не попадающие в новый тип, просто отбрасываются. Не производится никакого округления или других действий для получения более корректного результата:
Видно, что знаковый бит при сужении не оказал никакого влияния, "^^ как был просто отброшен — результат приведения обратных чисел (384и -384) оказался одинаковым. Следовательно, может быть потеряно Не только точное абсолютное значение, но и знак величины.
Это верно и для типа char:
char с=40000; Pnnt((short)c);
Результатом будет:
-25536
Сужение дробного типа до целочисленного является более сложной процедурой. Она проводится в два этапа.
На первом шаге дробное значение преобразуется в long, если целевым типом является long, или в int — в противном случае (целевой тип byte, short, char или int). Для этого исходное дробное число сначала математически округляется в сторону нуля, то есть дробная часть просто отбрасывается.
Например, число 3,84 будет округлено до 3, а -3,84превратится в -3. При этом могут возникнуть особые случаи:
• если исходное дробное значение является Nan,то результатом первого шага будет 0 выбранного типа (т.е. int или long);
• если исходное дробное значение является положительной или отрицательной бесконечностью, то результатом первого шага будет, соответственно, максимально или минимально возможное значение для выбранного типа (т.е. для int или long);
• наконец, если дробное значение было конечной величиной, но в результате округления получилось слишком, большое по модулю число для выбранного типа (т.е. для int или long), то, как и в предыдущем пункте, результатом первого шага будет, соответственно, максимально или минимально возможное значение этого типа. Если же результат округления укладывается в диапазон значений выбранного типа, то он и будет результатом первого шага.
На втором шаге производится дальнейшее сужение от выбранного целочисленного типа к целевому, если таковое требуется, то есть может иметь место дополнительное преобразование от int кbyte, short или char.
Проиллюстрируем описанный алгоритм преобразованием от бесконечности ко всем целочисленным типам: