Вітання! Під час проходження JavaRush ти неодноразово стикався з примітивними типами. Ось короткий список того, що ми про них знаємо:
Але, крім значень, типи відрізняються ще й розміром у пам'яті.
Усередині матрьошки є вільне місце. Чим більше матрьошка – тим більше місця. Всередину великої матрьошки
Ми записуємо це значення в змінну
Саме тому компілятор “просив підтвердження” у формі явного приведення до конкретного типу. По-перше, воно показує, що ти береш відповідальність за результат на себе, а по-друге, вказує компілятор скільки місця виділити при наведенні типів. Адже якби ми в останньому прикладі приводабо
Для типу
Головне — розуміти принцип зберігання значень
Так ось. Коли ми виробляємо додавання
- Вони не є об'єктами і є значенням, що зберігається в пам'яті
- Примітивні типи бувають кількох видів:
- Цілі числа -
byte,short,int,long - Числа з плаваючою точкою (дрібні) -
floatіdouble - Логічний -
boolean - Символьний (для позначення букв та цифр)
char
- Цілі числа -
- Кожен має свій діапазон значень:
| Примітивний тип | Розмір у пам'яті | Діапазон значень |
|---|---|---|
| byte | 8 біт | від -128 до 127 |
| short | 16 біт | до -32768 до 32767 |
| char | 16 біт | від 0 до 65536 |
| int | 32 біта | від -2147483648 до 2147483647 |
| long | 64 біта | від -9223372036854775808 до 9223372036854775807 |
| float | 32 біта | від (2 у ступені -149) до ((2-2 у ступені -23)*2 у ступені 127) |
| double | 64 біта | від (-2 у ступені 63) до ((2 у ступені 63) - 1) |
| boolean | 8 (при використанні в масивах), 32 (при використанні не в масивах) | true або false |
intзаймає більше, ніж byte. А long- більше, ніж short. Об'єм займаної примітивами пам'яті можна порівняти з матрьошками:
Усередині матрьошки є вільне місце. Чим більше матрьошка – тим більше місця. Всередину великої матрьошки longми легко можемо покласти меншу за розміром int. Вона легко вміститься, і нічого робити додатково не потрібно. У Java під час роботи з примітивами це називається автоматичним перетворенням. Інакше його називають розширенням. Ось простий приклад розширення:
public class Main {
public static void main(String[] args) {
int bigNumber = 10000000;
byte littleNumber = 16;
bigNumber = littleNumber;
System.out.println(bigNumber);
}
}
Тут ми привласнюємо значення byteзмінну int. Привласнення пройшло успішно і без будь-яких проблем: значення, що зберігається в byte, займає менший обсяг у пам'яті, ніж "влазить" в int. "Маленька матрьошка" (значення byte) легко влазить у "велику матрьошку" (змінну int). Інша річ, коли ти намагаєшся зробити навпаки — покласти значення великого розміру в змінну, яка не розрахована на такі розміри. Зі справжніми матрьошками такий номер у принципі не пройде, а в Java — минеться, але з нюансами. Давай спробуємо покласти значення intв змінну short:
public static void main(String[] args) {
int bigNumber = 10000000;
short littleNumber = 1000;
littleNumber = bigNumber;//помилка!
System.out.println(bigNumber);
} Помилка! Компілятор розуміє, що ти намагаєшся зробити щось нестандартне і засунути велику матрьошку ( int) всередину маленької ( short). Помилка компіляції у разі — попередження від компілятора: “ Гей, ти точно впевнений, що це хочеш? ” Якщо ти певен, говориш про це компілятору: “ Все ок, я знаю, що роблю! ” Цей процес називається явним перетворенням типів, або звуженням . Щоб зробити звуження, тобі необхідно вказати тип, до якого ти хочеш привести своє значення. Іншими словами, відповісти компілятору на його запитання: " Ну і в яку з цих маленьких матрьошок ти хочеш засунути цю велику матрьошку?" ” У нашому випадку це буде виглядати так:
public static void main(String[] args) {
int bigNumber = 10000000;
short littleNumber = 1000;
littleNumber = (short) bigNumber;
System.out.println(littleNumber);
} Ми явно вказали, що хочемо помістити значення intу змінну shortта беремо відповідальність на себе. Компілятор, бачачи явну вказівку більш вузький тип, проводить перетворення. Яким буде результат? Висновок: -27008 Трохи несподівано. Чому саме такий? Насправді, все просто. У нас було початкове значення - 10000000 Воно зберігалося в змінній int, яка займала 32 біти, і в двійковій формі воно виглядало так:
Ми записуємо це значення в змінну short, але вона може зберігати лише 16 біт! Відповідно, лише перші 16 біт нашого числа будуть туди переміщені, решта — відкинуться. У результаті змінну shortпотрапить значення
Саме тому компілятор “просив підтвердження” у формі явного приведення до конкретного типу. По-перше, воно показує, що ти береш відповідальність за результат на себе, а по-друге, вказує компілятор скільки місця виділити при наведенні типів. Адже якби ми в останньому прикладі приводабо intдо типу byte, а не до short, у розпорядженні було б тільки 8 біт, а не 16, і результат був би іншим. Для дробових типів ( floatі double) звуження відбувається по-своєму. Якщо спробувати привести таке число до цілого типу, у нього буде відкинута дробова частина.
public static void main(String[] args) {
double d = 2.7;
long x = (int) d;
System.out.println(x);
}Виведення в консоль: 2
Тип даних char
Ти вже знаєш, що тип char використовується для відображення окремих символів.public static void main(String[] args) {
char c = '!';
char z = 'z';
char i = '8';
} Але він має ряд особливостей, які важливо розуміти. Давай ще раз подивимося в таблицю з діапазонами значень:
| Примітивний тип | Розмір у пам'яті | Діапазон значень |
|---|---|---|
| byte | 8 біт | від -128 до 127 |
| short | 16 біт | від -32768 до 32767 |
| char | 16 біт | від 0 до 65536 |
| int | 32 біта | від -2147483648 до 2147483647 |
| long | 64 біта | від -9223372036854775808 до 9223372036854775807 |
| float | 32 біта | від (2 у ступені -149) до ((2-2 у ступені -23)*2 у ступені 127) |
| double | 64 біта | від (-2 у ступені 63) до ((2 у ступені 63)-1) |
| boolean | 8 (при використанні в масивах), 32 (при використанні не в масивах) | true або false |
charвказаний числовий діапазон від 0 до 65536. Але що це означає? Адже char— це не лише цифри, а й букви, розділові знаки… Справа в тому, що значення charзберігаються в Java у форматі Юнікоду. Ми вже стикалися з Юнікодом в одній із минулих лекцій. Ти, напевно, пам'ятаєш, що Unicode — це стандарт кодування символів, що включає знаки майже всіх письмових мов світу. Інакше кажучи, це список спеціальних кодів, у якому знайдеться код майже будь-якого символу з мови. Загальна таблиця Юнікод дуже велика, і, звичайно, її не потрібно вчити напам'ять. Ось, наприклад, її шматочок:
Головне — розуміти принцип зберігання значень charі пам'ятати, що знаючи код конкретного символузавжди можна отримати його у програмі. Давай спробуємо це зробити з якимось випадковим числом:
public static void main(String[] args) {
int x = 32816;
char c = (char) x ;
System.out.println(c);
}Висновок в консоль: 耰 Саме в такому форматі Java зберігаються символи char. Кожному символу відповідає число - числовий код розміром 16 біт, або два байти. Юнікоду 32816 відповідає ієрогліф 耰. Зверни увагу на якийсь момент. У цьому прикладі ми використали змінну int. Вона займає в пам'яті 32 біти , тоді як char- 16 . Тут ми вибрали int, тому що потрібне число 32816 знаходиться за межами діапазону short. Хоча розмір char, як і short, дорівнює 16 біт, але в діапазоні charнемає негативних чисел, тому "позитивний" діапазон charвдвічі більше (65536 замість 32767 у short). Ми можемо використовуватиint, Поки наш код вкладається в діапазон до 65536. Але якщо створити число int >65536, воно займатиме більше 16 бітів. І при звуженні типів:
char c = (char) x; зайві біти будуть відкинуті, і результат буде несподіваним.
Особливості складання char і цілих чисел
Давай розглянемо такий незвичайний приклад:public class Main {
public static void main(String[] args) {
char c = '1';
int i = 1;
System.out.println(i+c);
}
}Висновок у консоль: 50 O_О Де логіка? 1+1, звідки взялося 50?! Ти вже знаєш, що значення charзберігаються в пам'яті як числа в діапазоні від 0 до 65536, що позначають юнікод нашого символу.
Так ось. Коли ми виробляємо додавання charі якогось цілого типу, charперетворюється на число, яке відповідає йому в Юнікоді. Коли в нашому коді ми складали 1 і '1' — символ '1' перетворився на свій код, який дорівнює 49 (можеш перевірити в таблиці вище). Тому результат і дорівнював 50. Давай ще раз візьмемо для прикладу нашого старого друга —耰, і спробуємо скласти його з якимось числом.
public static void main(String[] args) {
char c = '耰';
int x = 200;
System.out.println(c + x);
}Висновок в консоль: 33016 Ми вже з'ясували, що відповідає коду 32816. А при складанні цього числа і 200 ми отримуємо якраз наш результат — 33016 :) Механізм роботи, як бачиш, досить простий.
ПЕРЕЙДІТЬ В ПОВНУ ВЕРСІЮ