Чтение онлайн

на главную - закладки

Жанры

Программирование на Java
Шрифт:

Введение

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

Например:

long a=3;

a = 5+'A'+a;

print("a="+Math.round(a/2F));

Рассмотрим, как в этом примере компилятор устанавливает тип каждого выражения и какие преобразования (conversion)

типов необходимо осуществить при каждом действии.

* В первой строке литерал 3 имеет тип по умолчанию, то есть int. При присвоении этого значения переменной типа long необходимо провести преобразование.

* Во второй строке сначала производится сложение значений типа int и char. Второй аргумент будет преобразован так, чтобы операция проводилась с точностью в 32 бита. Второй оператор сложения опять потребует преобразования, так как наличие переменной a увеличивает точность до 64 бит.

* В третьей строке сначала будет выполнена операция деления, для чего значение long надо будет привести к типу float, так как второй операнд - дробный литерал. Результат будет передан в метод Math.round, который произведет математическое округление и вернет целочисленный результат типа int. Это значение необходимо преобразовать в текст, чтобы осуществить дальнейшую конкатенацию строк. Как будет показано ниже, эта операция проводится в два этапа - сначала простой тип приводится к объектному классу-"обертке" (в данном случае int к Integer ), а затем у полученного объекта вызывается метод toString, что дает преобразование к строке.

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

Вспомним уже рассмотренный пример:

int b=1;

byte c=(byte)-b;

int i=c;

Здесь во второй строке необходимо провести явное преобразование, чтобы присвоить значение типа int переменной типа byte. В третьей же строке обратное приведение производится автоматически, неявным для разработчика образом.

Рассмотрим сначала, какие переходы между различными типами можно осуществить.

Виды приведений

В 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. Хотя эти дробные типы вмещают гораздо большие числа, чем соответствующие целые, но у них меньше значащих разрядов.

Поделиться:
Популярные книги

Газлайтер. Том 18

Володин Григорий Григорьевич
18. История Телепата
Фантастика:
попаданцы
аниме
фэнтези
6.80
рейтинг книги
Газлайтер. Том 18

Социология

Гидденс Энтони
Научно-образовательная:
обществознание
5.00
рейтинг книги
Социология

Вендиго (сборник)

Блэквуд Элджернон Генри
Гримуар
Фантастика:
ужасы и мистика
7.88
рейтинг книги
Вендиго (сборник)

Тайные тропы

Брянцев Георгий Михайлович
Военные приключения
Проза:
военная проза
6.14
рейтинг книги
Тайные тропы

Лунный бассейн. Металлическое чудовище (сборник)

Меррит Абрахам Грэйс
2. Абрахам Меррит. Собрание сочинений в 5 томах
Фантастика:
ужасы и мистика
5.00
рейтинг книги
Лунный бассейн. Металлическое чудовище (сборник)

Приход ночи

Азимов Айзек
Фантастика:
научная фантастика
7.73
рейтинг книги
Приход ночи

Барон Бранд Берс. Том 3

Limonad
3. Бранд Берс
Проза:
магический реализм
5.00
рейтинг книги
Барон Бранд Берс. Том 3

Заговор Аквитании

Ладлэм Роберт
Детективы:
политические детективы
5.00
рейтинг книги
Заговор Аквитании

Мир фантастики 2014. День Десантника (сборник)

Ясинская Марина Леонидовна
Мир фантастики 2014
Фантастика:
научная фантастика
космическая фантастика
7.00
рейтинг книги
Мир фантастики 2014. День Десантника (сборник)

Гарвардский баг

Вольная Мира
Любовные романы:
любовно-фантастические романы
5.00
рейтинг книги
Гарвардский баг

Две могилы

Престон Дуглас
12. Пендергаст
Детективы:
триллеры
прочие детективы
8.90
рейтинг книги
Две могилы

Дьявольские миры (Сборник)

Смит Джордж Генри
4. Фантастический боевик
Фантастика:
ужасы и мистика
6.25
рейтинг книги
Дьявольские миры (Сборник)

Письма к тайной возлюбленной

Блейк Тони
Любовные романы:
современные любовные романы
8.72
рейтинг книги
Письма к тайной возлюбленной

Князь Андер Арес 5

Грехов Тимофей
5. Андер Арес
Фантастика:
историческое фэнтези
фэнтези
героическая фантастика
5.00
рейтинг книги
Князь Андер Арес 5