Преобразование типов в Java
Данная статья:
- написана командой Vertex Academy. Надеемся, что она Вам будет полезна. Приятного прочтения!
- это одна из статей из нашего "Самоучителя по Java"
Преобразование типов - это тема, которая может показаться сложной начинающим программировать на Java. Однако, заверим Вас, на самом деле всё просто. Главное понять по каким законам происходит взаимодействие между переменными и помнить об этом при написании программ. Итак, давайте разбираться.
В Java существует 2 типа преобразований - картинка Вам в помощь:
Напомним, что вся "Вселенная Java" состоит из:
- примитивных типов (byte, short, int, long, char, float, double, boolean)
- объектов
В данной статье мы:
- рассмотрим преобразование типов для примитивных типов переменных
- преобразование объектов (String, Scanner и др.) в этой статье не рассматривается, поскольку с объектами происходит отдельная «магия» - это тема для отдельной статьи.
Автоматическое преобразование
Ну, что ж, давайте попробуем разобраться что такое "автоматическое преобразование".
Помните, когда мы рассматривали типы переменных (в статье "Переменные в Java. Создание переменной"), мы говорили, что переменная - это некоторый «контейнер», в котором может храниться значение для дальнейшего использования в программе. Также мы говорили о том, что каждый тип переменной имеет свой диапазон допустимых значений и объем занимаемой памяти. Вот она табличка, где это все было расписано:
Так вот, к чему мы, собственно говоря, клоним. К тому, что совсем не просто так Вам давались диапазоны допустимых значений и объем занимаемой памяти 🙂
Давайте, сравним, например:
1. byte и short. byte имеет меньший диапазон допустимых значений, чем short. То есть byte это как бы коробочка поменьше, а short - это коробочка побольше. И значит, мы можем byte вложить в short.
2. byte и int. byte имеет меньший диапазон допустимых значений, чем int. То есть byte это как бы коробочка поменьше, а int - это коробочка побольше. И значит, мы можем byte вложить в int.
3. int и long. int имеет меньший диапазон допустимых значений, чем long. То есть int это как бы коробочка поменьше, а long - это коробочка побольше. И значит, мы можем int вложить в long.
Это и есть пример автоматического преобразования. Это можно схематически изобразить в виде вот такой картинки:
Давайте рассмотрим как это работает на практике.
Пример №1
Код №1 - если Вы запустите это код на своем компьютере, в консоли будет выведено число 15
1 2 3 4 5 6 7 8 |
class Test { public static void main(String[] args) { byte a = 15; byte b = a; System.out.println(b); } } |
Код №2 - если Вы запустите это код на своем компьютере, в консоли будет выведено число 15
1 2 3 4 5 6 7 8 |
class Test { public static void main(String[] args) { byte a = 15; int b = a; System.out.println(b); } } |
И-и-и? Вы думаете, что раз в консоль было выведено одно и то же число, и код №1 отличается от кода №2 всего лишь типом переменной b, то между ними нет никакой разницы? Это не так.
В коде №2 присутствует автоматическое преобразование типов, а в коде №1 - нет:
Хотя число, в принципе, одно и то же, но теперь оно находится в большем контейнере, который занимает больше места на диске. При этом, JVM выполняет автоматические преобразования за Вас. Она знает, что int больше чем byte.
Приведение типов
Другое дело если вы пытаетесь переложить что-то из большего контейнера в более маленький.
Вы можете знать, что в большем контейнере лежит то, что поместиться и в маленьком – но об этом не знает JVM, и пытается предохранить вас от ошибок.
Поэтому, вы должны «прямо сказать», что ситуация под контролем:
1 2 3 4 5 6 7 |
class Test { public static void main(String[] args) { int a=0; long b=15; a = (int) b; } } |
Тут мы дописали (int) перед b. Если бы переменная a была, к примеру, типа byte, в скобках бы стояло (byte). Общая формула выглядит так:
Она говорит "сделай из (большего) значения b переменную нужного мне (целевого) типа int".
Если что-то пошло не так.
До этого мы рассматривали ситуации, предполагая, что мы точно знаем, что делаем. Но что если попытаться поместить в контейнер то, что туда не помещается?
Оказывается, в контейнере останется лишь то, что туда «влезло». К примеру, у чисел с плавающей точкой будет «отсекаться» дробная часть:
1 2 3 4 5 6 7 8 9 |
//пример 1 class Test { public static void main(String[] args) { double a=11.2345; int b=(int)a; System.out.println(b); // в консоли получится число 11 } } |
Надо помнить, что дробная часть не округляется, а отбрасывается.
А что будет, если мы попытаемся поместить число, которое выходит за допустимые границы? Например, если в byte (диапазон byte от -128 до 127) положить число 128? Думаете, мы получим 1? Нет. Мы получим -128:
1 2 3 4 5 6 7 |
class Test { public static void main(String[] args) { double a=128; byte b=(byte)a; System.out.println(b); //в консоли увидим -128 } } |
Значение переменной при таком преобразовании можно рассчитать, но цель программиста – не допускать ситуации, когда значение выходит за допустимые границы, поскольку это может привести к неправильной работе программы.
Задания:
- Последовательно пропишите в компиляторе преобразования всех примитивных типов друг к другу, включая типы char и Составьте таблицу такого вида:
byte | short | char | int | long | float | double | boolean | |
byte | ||||||||
short | ||||||||
char | ||||||||
int | ||||||||
Long | ||||||||
Float | ||||||||
double | ||||||||
boolean |
На пересечении напишите: а – если преобразование происходит автоматически, на – если нужно использовать явное преобразование, х – если преобразование невозможно.
* приведение типа к самому себе называется тождественным – его прописывать не обязательно
- Посмотрите еще раз, какой размер имеет каждый примитивный тип. Попытайтесь составить блок-схему, показывающую, куда помещаются какие типы. Проведите стрелочки с надписью «расширяющее преобразование» и «сужающее преобразование».
Вопросы
На собеседовании на должность Junior Java Developer Вас могут спросить:
Что Вы знаете о преобразовании примитивных типов данных, есть ли потеря данных, можно ли преобразовать логический тип?
Попробуйте ответить на вопрос.
Подытожим:
- Если Вы "кладёте" в больший контейнер содержимое меньшего контейнера», преобразование происходит автоматически, и ошибок возникать не должно.
- Если есть необходимость положить «значение из большего контейнера в меньший», нужно быть осторожным, и пользоваться явным приведением типов.
- При приведении float или double к целочисленным типам, дробная часть не округляется, а просто отбрасывается.
- Тип boolean не приводится ни к одному из типов.
- Тип char приводится к числовым типам, как код символа в системе UNICODE.
- Если число больше своего контейнера, результат будет непредсказуемым.
В этой статье описана только часть материала на тему приведения типов. Существуют также приведения объектных типов, приведение к строке (ведь в строке может быть записано все что угодно, правда?) и автоматическое продвижение типов в выражениях.
Надеемся, что наша статья была Вам полезна. Также есть возможность записаться на наши курсы по Java в Киеве. Обучаем с нуля. Детальную информацию Вы можете найти у нас на сайте.