Порівняння об'єктів типу Integer
за допомогою ==
може дати непослідовні результати. Ось посібник, щоб зрозуміти Integer
; equals()
проти ==
, і як правильно їх використовувати
Integer
є обгорткою для примітивного типу int
у Java.
Що таке класи-обгортки? Класи-обгортки дають можливість використовувати примітивні типи даних (int, boolean тощо) як об'єкти. Це як упакувати простий подарунок (примітивний тип даних, як-от int
) у розкішну декоративну обгортку (наприклад, Integer
), щоб його можна було використовувати в більш гнучкий і потужний спосіб.
Підожди, у чому різниця між equals()
і ==
?
Уявімо, що у вас є дві копії однієї й тієї ж книги.
- У Java оператор
==
перевіряє, чи є два об'єкти (у цьому випадку, дві книги) одним і тим самим об'єктом. В даному випадку це не так; дві книги — це окремі фізичні копії. - З іншого боку, метод
equals()
перевіряє, чи є вміст/значення двох об'єктів однаковими. Тут так, вміст двох книг ідентичний. Кожна сторінка в одній книзі така ж, як відповідна сторінка в іншій.
Але чому ==
працює в деяких випадках?
Давайте розглянемо наступний приклад:
public class IntegerExample {
public static void main(String[] args) {
//Випадок 1
Integer x = 100;
Integer y = 100;
System.out.println(x == y); // true
//Випадок 2
Integer m = 200;
Integer n = 200;
System.out.println(m == n); // false
}
}
Це плутає, правда? Чому один випадок спрацював, а інший — ні?
Ось чому: Java використовує кешування для оптимізації продуктивності та ефективності пам'яті. Для діапазону від -128
до 127
Java повторно використовує об'єкти за посиланням.
Що це взагалі означає??? Дозвольте пояснити:
Коли ви створюєте об'єкт, Java виділяє йому місце. Для діапазону від -128
до 127
об'єкт створюється в кеш-області хіпу, і якщо кілька змінних ініціалізовано однаковим значенням, замість створення кількох екземплярів, Java вказує всі ці змінні на одне й те саме місце. Але для значень поза цим діапазоном для кожної нової змінної виділяється нове місце/пам'ять. Використання одного й того самого екземпляра заощаджує пам'ять.
Ось чому в випадку 1 ми отримуємо true
, тому що ==
порівнює адреси об'єктів, і в даному випадку обидва значення x
і y
насправді вказують на один і той самий об'єкт. Але це не так для m
і n
.
Тому завжди використовуйте equals()
, тому що він завжди порівнюватиме вміст/значення, а не посилання.`
Покладання на ==
для порівняння об'єктів може призвести до несподіваних результатів в залежності від порівнюваних значень. Використання equals()
гарантує, що ваш код порівнюватиме фактичні значення, а не посилання в пам'яті.
Заключні зауваження та деякі поширені запитання, які можуть виникнути
- Це кешування для
Integer
працює тільки з автоматичним упаковуванням (auto-boxing). Об'єктиInteger
не кешуються, коли вони створюються за допомогою конструктора, тобто:
Integer x = new Integer(100)
- Що таке автоматичне упаковування (auto-boxing)? Це автоматичне перетворення між примітивними типами даних і їх відповідними класами-обгортками.
- Кешування застосовується й до інших класів-обгорток, таких як
Character
(ASCII 0 до 127),
Boolean
(true/false),
Byte
,Short
,Long
(-128 до 127). - Чи можна збільшити ліміт кешування? Так, це можна налаштувати за допомогою опції JVM
-XX:AutoBoxCacheMax
. - Що відбувається з змінною
y
у пам'яті, якщо я оновлю зміннуx
у наведеному вище прикладі наx = 150
?
Integer
є незмінним (immutable), тому Java автоматично створює новий екземпляр для змінної, коли виконуються операції для зміни її значення. Тому тутx
тепер буде вказувати на новий екземпляр зі значенням 150, аy
вказуватиме на те саме старе місце зі значенням 100.
Перекладено з: Always use equals() to compare Integer Objects in Java