1. Сравняване на обекти в Java
В Java обектите могат да се сравняват Howто по препратка, така и по стойност.
Сравняване на референции
Ако две променливи сочат към един и същ обект в паметта, тогава препратките, съхранени в тези променливи, са равни. Ако сравните тези променливи с помощта на оператора за equalsство ( ==
), получавате true и този резултат има смисъл. Тук всичко е просто.
Код | Конзолен изход |
---|---|
|
|
Сравнение по стойност
Но често можете да срещнете ситуации, при които две променливи се отнасят до два различни обекта, които са идентични. Например два различни низови обекта, които съдържат един и същи текст.
За да определите дали различните обекти са идентични, използвайте equals()
метода. Например:
Код | Конзолен изход |
---|---|
|
|
Методът equals
не е ограничен до String
класа. Всеки клас го има.
Дори класове, които пишете сами, и ето защо.
2. Object
клас
Всички класове в Java наследяват Object
класа. Създателите на Java измислиха този подход.
И ако един клас наследи Object
класа, тогава той получава всички методи на Object
класа. И това е основна последица от наследството.
С други думи, всеки клас има методите на Object
класа, дори ако техният code не ги споменава.
Тези наследени методи включват методи, свързани със сравнение на обекти. Това са методите equals()
и hashCode()
.
Код | В действителност, ето Howво ще имаме: |
---|---|
|
|
В примера по-горе създадохме прост Person
клас с параметри за име и възраст, но не и един метод. Но тъй като всички класове наследяват Object
класа, Person
класът автоматично има два метода:
Метод | Описание |
---|---|
|
Сравнява текущия обект и преминалия обект |
|
Връща хеш codeа на текущия обект |
Оказва се, че абсолютно всеки обект има equals
метод и обекти от различни типове могат да се сравняват помежду си. Такъв code ще се компorра и ще работи перфектно.
Код | Конзолен изход |
---|---|
|
|
|
|
3. equals()
метод
Методът equals()
, наследен от Object
класа, прилага най-простия алгоритъм за сравняване на текущия обект с преминалите обекти: той просто сравнява препратките към обектите.
Получавате същия резултат, ако просто сравнявате Person
променливи, instead of да извиквате equals()
метода. Пример:
Код | Конзолен изход |
---|---|
|
|
Когато equals
методът се извика на a
, той просто сравнява препратката, съхранена в a
променливата, с препратката, съхранена в b
променливата.
Сравнението обаче работи по различен начин за String
класа. Защо?
Защото хората, които са създали String
класа, са написали своя собствена реализация на equals()
метода.
Реализация на equals()
метода
Сега нека напишем нашата собствена реализация на метода equals в Person
класа. Ще разгледаме 4 основни случая.
equals
метода, той винаги приема Object
обект като аргумент
Сценарий 1 : същият обект, на който equals
се извиква методът, също се предава на equals
метода. Ако препратките на текущия обект и предадения обект са равни, методът трябва да върне true
. Един обект е equals на себе си.
В codeа ще изглежда така:
Код | Описание |
---|---|
|
Сравнете препратките |
Сценарий 2 : null
предава се на equals
метода — нямаме с Howво да сравняваме. Обектът, на който equals
се извиква методът, определено не е null, така че трябва да се върнем false
в този случай.
В codeа ще изглежда така:
Код | Описание |
---|---|
|
Сравнете препратките Предаденият обект ли е null ? |
Сценарий 3Person
: на метода се предава препратка към обект, който не е a equals
. Обектът equals ли е Person
на непредмета Person
? Това е въпрос, който разработчикът на Person
класа трябва да реши, Howто той or тя иска.
Но обикновено обектите трябва да са от един и същи клас, за да се считат за равни. Следователно, ако нещо различно от обект от Person
класа се предаде на нашия метод equals, тогава ние винаги ще връщаме false
. Как можете да проверите вида на обект? Точно така — с помощта на instanceof
оператора.
Ето How изглежда нашият нов code:
Код | Описание |
---|---|
|
Сравнете препратките Предаденият обект ли е null ? Ако предаденият обект не е a Person |
4. Сравнение на два Person
обекта
Какво завършихме? Ако сме стигнали до края на метода, тогава имаме Person
препратка към обект, която не е null
. Затова го преобразуваме в a Person
и сравняваме съответните вътрешни данни на двата обекта. И това е нашият четвърти сценарий .
Код | Описание |
---|---|
|
Сравнете препратките Предаденият обект ли е null ? Ако предаваният обект не е Person Typecasting |
И How сравнявате два Person
обекта? Те са равни, ако имат едно и също име ( name
) и възраст ( age
). Крайният code ще изглежда така:
Код | Описание |
---|---|
|
Сравнете препратките Предаденият обект ли е null ? Ако предаваният обект не е Person Typecasting |
Но това не е всичко.
Първо, полето за име е String
, така че трябва да сравните полето за име, като извикате equals
метода.
this.name.equals(person.name)
Второ, name
полето може да бъде null
: в този случай не можете да equals
го използвате. Имате нужда от допълнителна проверка за null
:
this.name != null && this.name.equals(person.name)
Въпреки това, ако полето за име е null
и в двата Person
обекта, тогава имената все още са равни.
Кодът за четвъртия сценарий може да изглежда така:
|
Ако възрастите не са равни, веднага return false Ако this.name е равно на null , няма смисъл да се сравнява с помощта на equals метода. Тук or второто name поле е равно на null , or не е. Сравнете двете полета за имена, като използвате equals метода. |
5. hashCode()
метод
В допълнение към equals
метода, който е предназначен да извърши подробно сравнение на всички полета на двата обекта, има друг метод, който може да се използва за неточно, но много бързо сравнение: hashCode()
.
Представете си, че подреждате по азбучен ред списък от хиляди думи и трябва многократно да сравнявате двойки думи. И думите са дълги, състоящи се от много букви. Най-общо казано, подобно сравнение ще отнеме много време.
Но може да се ускори. Да предположим, че имаме думи, които започват с различни букви - веднага става ясно, че са различни. Но ако започват с едни и същи букви, тогава все още не можем да кажем Howъв ще бъде резултатът: думите може да се окажат еднакви or различни.
Методът hashCode()
работи на подобен принцип. Ако го извикате на обект, той връща няHowво число — аналогично на първата буква в думата. Това число има следните свойства:
- Идентични обекти винаги имат един и същ хешcode
- Различните обекти могат да имат един и същ хешcode or техните хешcodeове могат да бъдат различни
- Ако обектите имат различни хешcodeове, тогава обектите определено са различни
За да направим това още по-ясно, нека преформулираме тези свойства по отношение на думи:
- Еднаквите думи винаги имат еднакви първи букви.
- Различните думи могат да имат еднакви първи букви or техните първи букви могат да бъдат различни
- Ако думите имат различни първи букви, то думите определено са различни
Последното свойство се използва за ускоряване на сравнението на обекти:
Първо се изчисляват хеш codeовете на двата обекта. Ако тези хешcodeове са различни, тогава обектите определено са различни и няма нужда да ги сравнявате допълнително.
Но ако хешcodeовете са еднакви, тогава все пак трябва да сравним обектите с помощта на метода equals.
6. Договори в code
Поведението, описано по-горе, трябва да се изпълнява от всички класове в Java. По време на компилация няма начин да се провери дали обектите са сравнени правилно.
Java програмистите имат универсално споразумение, че ако напишат своя собствена реализация на метода equals() и по този начин заменят стандартната имплементация (в класа Object
), те също трябва да напишат своя собствена реализация на hashCode()
метода по такъв начин, че гореспоменатите правила да са удовлетворен.
Това споразумение се нарича договор .
Ако внедрите само equals()
or само hashCode()
метода във вашия клас, тогава вие сте в грубо нарушение на договора (нарушor сте споразумението). не прави това
Ако други програмисти използват вашия code, той може да не работи правилно. Нещо повече, ще използвате code, който разчита на спазването на горните договори.
Когато търсите елемент, всички колекции на Java първо сравняват хешcodeовете на обектите и едва след това извършват сравнение с помощта на equals
метода.
Това означава, че ако дадете на собствения си клас equals
метод, но не напишете свой собствен hashCode()
метод or го внедрите неправилно, тогава колекциите може да не работят правилно с вашите обекти.
Например, можете да добавите обект към списък и след това да го търсите с помощта на contains()
метода, но колекцията може да не намери вашия обект.
GO TO FULL VERSION