Н.А. Вязовик - Программирование на Java
- Название:Программирование на Java
- Автор:
- Жанр:
- Издательство:неизвестно
- Год:неизвестен
- ISBN:нет данных
- Рейтинг:
- Избранное:Добавить в избранное
-
Отзывы:
-
Ваша оценка:
Н.А. Вязовик - Программирование на Java краткое содержание
Программирование на Java - читать онлайн бесплатно полную версию (весь текст целиком)
Интервал:
Закладка:
Рассмотрим сначала, какие переходы между различными типами можно осуществить.
Виды приведений
В Java предусмотрено семь видов приведений:
* тождественное (identity);
* расширение примитивного типа (widening primitive);
* сужение примитивного типа (narrowing primitive);
* расширение объектного типа (widening reference);
* сужение объектного типа (narrowing reference);
* преобразование к строке (String);
* запрещенные преобразования (forbidden).
Рассмотрим их по отдельности.
Тождественное преобразование
Самым простым является тождественное преобразование. В Java преобразование выражения любого типа к точно такому же типу всегда допустимо и успешно выполняется.
Зачем нужно тождественное приведение? Есть две причины для того, чтобы выделить такое преобразование в особый вид.
Во-первых, с теоретической точки зрения теперь можно утверждать, что любой тип в Java может участвовать в преобразовании, хотя бы в тождественном. Например, примитивный тип boolean нельзя привести ни к какому другому типу, кроме него самого.
Во-вторых, иногда в Java могут встречаться такие выражения, как длинный последовательный вызов методов:
print(getCity().getStreet().getHouse().getFlat().getRoom());
При исполнении такого выражения сначала вызывается первый метод getCity(). Можно предположить, что возвращаемым значением будет объект класса City. У этого объекта далее будет вызван следующий метод getStreet(). Чтобы узнать, значение какого типа он вернет, необходимо посмотреть описание класса City. У этого значения будет вызван следующий метод ( getHouse() ), и так далее. Чтобы узнать результирующий тип всего выражения, необходимо просмотреть описание каждого метода и класса.
Компилятор без труда справится с такой задачей, однако разработчику будет нелегко проследить всю цепочку. В этом случае можно воспользоваться тождественным преобразованием, выполнив приведение к точно такому же типу. Это ничего не изменит в структуре программы, но значительно облегчит чтение кода:
print((MyFlatImpl)(getCity().getStreet().getHouse().getFlat()));
Преобразование примитивных типов (расширение и сужение)
Очевидно, что следующие четыре вида приведений легко представляются в виде таблицы 7.1.
Таблица 7.1. Виды приведений.
простой тип, расширение |
ссылочный тип, расширение |
простой тип, сужение |
ссылочный тип, сужение |
Что все это означает? Начнем по порядку. Для простых типов расширение означает, что осуществляется переход от менее емкого типа к более емкому. Например, от типа byte (длина 1 байт) к типу int (длина 4 байта). Такие преобразования безопасны в том смысле, что новый тип всегда гарантированно вмещает в себя все данные, которые хранились в старом типе, и таким образом не происходит потери данных. Именно поэтому компилятор осуществляет его сам, незаметно для разработчика:
byte b=3;
int a=b;
В последней строке значение переменной b типа byte будет преобразовано к типу переменной a (то есть, 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. Хотя эти дробные типы вмещают гораздо большие числа, чем соответствующие целые, но у них меньше значащих разрядов.
Повторим этот пример:
long a=111111111111L;
float f = a;
a = (long) f;
print(a);
Результатом будет:
111111110656
Обратное преобразование - сужение - означает, что переход осуществляется от более емкого типа к менее емкому. При таком преобразовании есть риск потерять данные. Например, если число типа 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
При сужении целочисленного типа к более узкому целочисленному все старшие биты, не попадающие в новый тип, просто отбрасываются. Не производится никакого округления или других действий для получения более корректного результата:
print((byte)383);
print((byte)384);
print((byte)-384);
Результатом будет:
127
-128
-128
Видно, что знаковый бит при сужении не оказал никакого влияния, так как был просто отброшен - результат приведения обратных чисел (384 и -384) оказался одинаковым. Следовательно, может быть потеряно не только точное абсолютное значение, но и знак величины.
Это верно и для типа char:
char c=40000;
print((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.
Читать дальшеИнтервал:
Закладка: