Java відноситься до мов з сильною типізацією - це означає, що під час компіляції практично завжди здійснюється перевірка на сумісність типів. Java запобігає невірні привласнення, забороняючи всі скільки-небудь сумнівні операції, та підтримує механізм приведення типів для тих випадків, коли сумісність може бути перевірена тільки під час виконання програми. Ми будемо розглядати приведення типів на прикладі операції привласнення, але все сказане відноситься і до перетворень всередині виразів, і до привласнення значень параметрам методів.
5.13.1. Неявне приведення типів
Java також підтримує неявні приведення цілих типів в типи з плаваючою точкою, але не навпаки - при такому переході не відбувається втрати значущості, так як діапазон значень з плаваючою точкою ширше, ніж у будь-якого з цілих типів.
Збереження діапазону не слід плутати зі збереженням точності. При деяких неявних перетвореннях можлива втрата точності. Наприклад, розглянемо перетворення long в float. Значення float є 32-розрядними, а значення long -
64-розрядними. float містить менше значущих цифр, ніж long, навіть незважаючи на те,
що цей тип здатний зберігати числа з більшого діапазону. Присвоєння значення long
змінної типу float може привести до втрати даних. Розглянемо наступний фрагмент:
long orig = 0x7effffffffffffffL;
float fval = orig;
long lose = (long) fval;
System.out.println ( "orig =" + orig); System.out.println ( "fval =" + fval); System.out.println ( "losw =" + lose);
Перші два оператора створюють значення long і привласнюють його змінної float. Щоб продемонструвати, що при цьому відбувається втрата точності, ми виробляємо явне приведення fval до long і присвоюємо значення іншої змінної (явне приведення типів розглядається нижче). Результати, виведені програмою, дозволяють переконатися в тому, що значення float втратило частину своєї точності, так як значення вихідної змінної orig типу long відрізняється від того, що було отримано при явному зворотному приведення значення змінної fval до типу long:
orig = 9151314442816847871 fval = 9.15131e + 18
Значення null може бути присвоєно посиланням на об'єкт будь-якого типу, в тому числі й на засланні на масив.
5.13.2. Явна приведення і instanceof
Коли значення одного типу не може бути присвоєно змінної іншого типу за допомогою неявного приведення, досить часто можна скористатися явним приведенням типів (cast). Явна приведення вимагає, щоб нове значення нового типу якнайкраще відповідало старому значенням старого типу. Деякі явні приведення неприпустимі (ви не зможете перетворити boolean в int), проте дозволяється, наприклад, явне приведення double до значення типу long, як показано в наступному фрагменті:
Коли значення з плаваючою точкою перетвориться до цілого типу, його дрібна частина відкидається; наприклад, (int) -72.3 дорівнює -72. У класі Math є методи, які інакше здійснюють округлення чисел з плаваючою точкою при перетворенні в ціле - див. "Клас Math".
Значення double також може явно перетворюватися до типу float, а значення цілого
типу - до меншого цілого типу. При приведенні double до float можлива втрата точності або ж поява нульового або нескінченного значення замість існуючого раніше кінцевого.
Приведення цілих типів полягає в "зрізанні" їх старших бітів. Якщо значення більшого цілого уміщається в меншому типі, до якого здійснюється перетворення, то нічого страшного не відбувається. Однак якщо величина більш широкого цілого типу лежить за межами вужчого типу, то втрата старших бітів змінює значення, а можливо - і знак. фрагмент:
System.out.println ( "s =" + s + ", b =" + b);
виводить наступний результат (оскільки старші біти s губляться при збереженні значення в b):
char можна перетворити до будь-якого цілого типу і навпаки. При приведенні цілого типу в char використовуються тільки молодші 16 біт, а інші біти відкидаються. При перетворенні char в цілий тип старші 16 біт заповнюються нулями. Проте згодом робота з цими бітами здійснюється точно так же, як і з будь-якими іншими. У наведеному нижче фрагменті програми максимальний символ Unicode перетвориться до типу int (неявно) і до типу short (явно). Значення типу int (0x0000ffff) виявляється позитивним, оскільки старші біти символу обнулені. Однак при приведенні до типу short виходить негативна величина, тому що старшим бітом типу short є знаковий біт:
public static void main (String [] args)
int i = '\ uffff';
short s = (short) '\ uffff';
System.out.println ( "i =" + i); System.out.println ( "s =" + s);
А ось як виглядає результат роботи:
Явна приведення типів може застосовуватися і до об'єктів. Хоча об'єкт розширеного типу дозволяється використовувати замість об'єкта супертіпа, зворотне, взагалі кажучи, невірно. Припустимо, у вас є такий ієрархія об'єктів:
Але іноді ви абсолютно точно знаєте, що об'єкт Coffee насправді є екземпляром класу Mocha. В цьому випадку можна здійснювати явне знижує приведення. Це робиться в такий спосіб:
Mocha fancy = (Mocha) joe;
Іноді метод не вимагає, щоб об'єкт ставився до розширеного типу, але може надати об'єктам розширеного типу додаткові функції. Можна виконати приведення типу і обробити виняток, проте використання винятків для подібних цілей виявляється порівняно повільним і тому вважається проявом поганого стилю. Для визначення того, чи стосується об'єкт до конкретного типу, застосовується метод instanceof, який повертає true для допустимих перетворень:
public void quaff (Coffee joe)
if (joe instanceof Mocha) // ... використовувати функціональність Mocha null instanceof Type завжди дорівнює false для будь-якого типу Type. 5.13.3. строкове приведення Клас String відрізняється від інших: це неявно використовується в операторі конкатенації +, а рядкові літерали посилаються на об'єкти String. Приклади нам вже зустрічалися в програмах: при виконанні конкатенації Java намагається перетворити в String все, що ще не належить до цього типу. Подібні приведення визначені для всіх примітивних типів і здійснюються викликом методу toString об'єкта (див. Розділ "Метод toString"). Якщо перетворити в String порожню посилання, то результатом буде рядок "null". Якщо для даного класу метод toString не визначений, то використовується метод, успадкований від класу Object і повертає строкове представлення типу об'єкта.Схожі статті