1. Перетворення типів
Змінні примітивних типів (за винятком типу boolean
) використовуються для зберігання чисел різних типів. І хоча типи змінних є незмінними, є спосіб, який дозволяє перетворювати типи. Цей спосіб — присвоювання.
Змінні різних типів можна присвоювати одна одній. У цьому разі значення, взяте зі змінної одного типу, буде перетворено на значення іншого типу й присвоєно другій змінній. Можна виділити два види перетворення типів: розширення і звуження.
Розширення типу схоже на перекладання з маленького кошика у великий — операція проходить непомітно і безболісно. Звуження типу — це перекладання з великого кошика в маленький: місця може не вистачити, і щось доведеться викинути.
Тут показано типи, відсортовані за розміром «кошика»:
2. Розширення типів
Часто може з'явитися потреба присвоїти змінній одного числового типу значення змінної іншого числового типу. Як же це зробити?
У мові Java є 4 цілочислових типи:
Тип | Розмір |
---|---|
byte |
1 байт |
short |
2 байти |
int |
4 байти |
long |
8 байтів |
Змінній більшого розміру завжди можна присвоювати змінні меншого розміру.
Змінній типу long
можна без обмежень присвоювати змінні типу int
, short
і byte
. Змінній типу int
можна присвоювати змінні типу short
і byte
. А змінній типу short
можна присвоювати змінні типу byte
.
Приклади:
Код | Опис |
---|---|
|
Такий код чудово скомпілюється. |
Таке перетворення — від типу меншого розміру до більшого, називається розширенням типу.
А як це діє для дійсних чисел?
З ними все так само — розмір має значення:
Тип | Розмір |
---|---|
float |
4 байти |
double |
8 байтів |
Змінній типу double
можна без проблем присвоїти змінну типу float
. А от з цілочисловими типами цікавіше.
Змінній типу float
можна присвоїти змінну будь-якого цілочислового типу. Навіть типу long
, довжина якого 8 байтів. А змінній типу double
можна взагалі присвоювати все що завгодно: змінну будь-якого цілочислового типу й змінну типу float
:
Код | Примітка |
---|---|
|
|
Зверніть увагу, що перетворення на дійсний тип може призвести до втрати точності внаслідок браку значущих цифр.
Під час перетворення цілих чисел на дробові можуть відкидатися наймолодші розряди числа. Але оскільки суть дробового числа в тому, щоб зберігати приблизне значення, таке присвоєння дозволено.
3. Звуження типів
А що там з іншими варіантами? Що робити, коли змінній типу int
потрібно присвоїти значення змінної типу long
?
Уявіть, що змінна — це кошик. Маємо кошики різного розміру: 1, 2, 4 і 8 байтів. Якщо перекладати пиріжки з меншого кошика в більший, проблем не виникає. А от якщо перекладати пиріжки з більшого кошика в менший, частина пиріжків може не вміститися.
Таке перетворення — від типу більшого розміру до меншого — називають звуженням типу. У разі такого присвоювання частина числа може просто не вміститися в нову змінну і «залишитися за бортом».
Під час звуження типу потрібно явно показати компілятору, що ми не помилилися, і відкидаємо частину числа свідомо. Для цього використовується оператор перетворення типу: це ім'я типу в круглих дужках.
У таких ситуаціях Java-компілятор вимагає від програміста вказувати оператор перетворення типу. Загальний вигляд цього оператора такий:
(тип) вираз
Приклади:
Код | Опис |
---|---|
|
Щоразу потрібно явно вказувати оператор перетворення типу |
У цьому випадку a
дорівнює 1
, і це здається зайвим. А якби a
мало більше значення?
Код | Опис |
---|---|
|
|
Мільйон чудово вміщується і в тип long
, і в тип int
. А от під час присвоювання мільйона змінній типу short
два перших байти було відкинуто, і залишилося тільки два останніх. А коли спробували записати мільйон у змінну типу byte
, взагалі залишився тільки один останній байт.
Будова чисел у пам'яті:
Тип | Двійковий запис | Десятковий запис |
---|---|---|
int |
0b00000000000011110100001001000000 | 1,000,000 |
short |
0b0100001001000000 | 16,960 |
byte |
0b01000000 | 64 |
Тип char
Тип char
, як і тип short
, займає в пам'яті два байти, але для перетворення одного з цих типів на інший завжди потрібно використовувати оператор перетворення типу. Річ у тім, що тип short
— знаковий і може містити значення від -32768
до +32767
, а тип char
— беззнаковий і може містити значення від 0
до 65535
.
У змінних типу char
не можна зберігати від'ємні числа, які можуть зберігатися в змінних типу short
. А в змінних типу short
не можна зберігати числа, більші за 32767
, які можуть зберігатися у змінних типу char
.
4. Тип виразу
А що робити, якщо в одному виразі використовуються змінні різних типів? Логічна відповідь — їх спочатку потрібно перетворити на один спільний тип. Але який?
Звісно ж, на тип більшого розміру.
У Java завжди відбувається перетворення на тип більшого розміру. У загальних рисах, спочатку відбувається розширення типу одного з членів операції, а вже потім — операція зі значеннями однакового типу.
Якщо у виразі є типи int
і long
, значення типу int
буде перетворено на тип long
, і тільки після цього його можна буде використовувати в операції:
Код | Опис |
---|---|
|
a буде розширено до типу long , і лише потім буде виконано додавання. |
Числа з рухомою крапкою
Якщо вираз містить ціле число й число з рухомою крапкою (float
/double
), ціле число буде перетворено на число з рухомою крапкою (float
/double
), і тільки потім буде виконано операцію з ними.
Якщо потрібно виконати операцію з числами float
і double
, то число типу float
буде перетворено на тип double
. Що, власне, й очікувалось.
Типи byte
, short
, char
під час взаємодії завжди перетворюються на тип int
. Недарма ж тип int
вважається стандартним цілочисловим типом.
Якщо помножити число типу byte
на число типу short
, отримаємо число типу int
. Якщо помножити число типу byte
на число типу byte
, отримаємо число типу int
. Навіть якщо скласти число типу byte
і число типу byte
, знову таки отримаємо число типу int
.
Для цього є кілька причин. Приклади:
Код | Опис |
---|---|
|
110 * 120 буде 13200 , це дещо перевищує максимальне значення типу byte : 127 |
|
110 + 120 буде 230 , це теж дещо перевищує максимальне значення типу byte : 127 |
У загальному випадку результатом множення числа довжиною 8 бітів (1 байт) на число довжиною 8 бітів (1 байт) буде число довжиною 16 бітів (2 байти).
Тому в усіх операціях з цілими типами, меншими за int
, ці типи завжди відразу перетворюються на тип int
. І якщо ви захочете зберегти результат обчислення у змінній, тип якої менший за int
, вам завжди доведеться явно вказувати операцію перетворення типу.
Приклади:
Код | Опис |
---|---|
|
вираз byte * byte матиме тип int |
|
вираз byte + byte матиме тип int |
|
вираз byte + int матиме тип int одиниця — це літерал типу int . |
5. Важливий момент
Операція перетворення типу має досить високий пріоритет.
Тому якщо у виразі є, скажімо, операції додавання й перетворення типу, то перетворення типу буде виконано перед додаванням.
Приклад:
Код | Опис |
---|---|
|
Оператор перетворення типу буде застосовано тільки до змінної a , яка й без того має тип byte . Код не скомпілюється. |
|
А отак правильно. |
Якщо ви хочете перетворити на певний тип увесь вираз, а не тільки один із його елементів, візьміть увесь вираз в круглі дужки і поставте перед ним оператор приведення типу.
ПЕРЕЙДІТЬ В ПОВНУ ВЕРСІЮ