1. Porównywanie obiektów w Javie
Obiekty w Javie można porównywać zarówno według referencji, jak i według wartości.
Porównanie linków
Jeśli dwie zmienne wskazują na ten sam obiekt w pamięci, to odwołania przechowywane w tych zmiennych są równe. Jeśli porównasz takie zmienne za pomocą operatora równości ==, otrzymasz prawdę, co ma sens. Tutaj wszystko jest proste.
| Kod | Wyjście na wyświetlaczu |
|---|---|
|
|
Porównanie według wartości
Często jednak można spotkać się z sytuacją, w której dwie zmienne odnoszą się do dwóch różnych, ale identycznych obiektów. Na przykład dwa wiersze zawierające ten sam tekst, ale znajdujące się w różnych obiektach.
Aby określić tożsamość różnych obiektów, musisz użyć equals()metody Example:
| Kod | Wyjście na wyświetlaczu |
|---|---|
|
|
equalsNie tylko klasa ma metodę – wszystkie klasy w ogóleString ją mają .
Nawet te, które tylko napiszesz, a oto dlaczego.
2. KlasaObject
Uważa się, że wszystkie klasy w Javie dziedziczą po Object. Tak to wymyślili twórcy Javy.
A jeśli pewna klasa jest dziedziczona z klasy Object, wszystkie metody klasy pojawiają się w tej klasie pochodnej Object. To jest główny efekt dziedziczenia.
Innymi słowy, każda klasa, nawet jeśli nie jest zapisana w swoim kodzie, ma wszystkie metody, które ma klasa Object.
A wśród tych metod są metody związane z porównywaniem obiektów. To jest metoda equals()i metoda hashCode().
| Kod | Jak to będzie w rzeczywistości: |
|---|---|
|
|
W powyższym przykładzie stworzyliśmy prostą klasę Personz parametrami nazwa i wiek, bez jednej metody. Jednak od wszystkie klasy są uważane za odziedziczone po klasie Object, klasa Personma ukryte dwie metody:
| metoda | Opis |
|---|---|
|
Porównuje bieżący obiekt i przekazany obiekt |
|
Zwraca kod skrótu bieżącego obiektu |
Okazuje się, że equalsabsolutnie wszystkie obiekty mają metody i można porównywać ze sobą obiekty różnych typów, a to wszystko się skompiluje i będzie działać idealnie.
| Kod | Wyjście na wyświetlaczu |
|---|---|
|
|
|
|
3. Metodaequals()
ObjectMetoda odziedziczona po klasie equals()zawiera najprostszy algorytm porównywania obiektów bieżących i przekazywanych - po prostu porównuje ich referencje.
Ten sam efekt uzyskasz, jeśli po prostu porównasz zmienne klasy Personzamiast wywoływać metodę equals().. Przykład:
| Kod | Wyjście na wyświetlaczu |
|---|---|
|
|
Metoda equalspo prostu porównuje wewnątrz łącza ai b.
Jednak w przypadku klasy Stringporównanie działa inaczej. Dlaczego?
Ponieważ twórcy klasy Stringnapisali własną implementację platformy equals().
Implementacja metodyequals()
Napiszmy własną implementację metody equals w Person. Spójrzmy na 4 główne przypadki.
equals, zawsze przyjmuje parametr typu
Object
Scenariusz 1 : equalsten sam obiekt został przekazany do metody, w której metoda została wywołana equals. Jeśli odniesienia bieżącego i przekazanego obiektu są równe, zwróć true. Obiekt pasuje do siebie.
W kodzie będzie to wyglądać tak:
| Kod | Opis |
|---|---|
|
Porównaj linki |
Scenariusz 2 : do metody equalsprzekazano odwołanie null- nie ma z czym porównywać. Obiekt, na który została wywołana metoda, equalsna pewno nie jest null, co oznacza, że w takim przypadku należy zwrócić false.
W kodzie będzie to wyglądać tak:
| Kod | Opis |
|---|---|
|
Porównaj referencje Obiekt przekazany — null? |
Scenariusz 3 : Do metody equalszostało przekazane odwołanie do obiektu bez klasy Person. Czy obiekt klasowy jest równy Personobiektowi nieklasowemu Person? Tutaj sam twórca klasy decyduje Person- zrobi, co zechce.
Ale zwykle obiekty są nadal uważane za równe, jeśli są obiektami tej samej klasy. Dlatego jeśli do naszej metody equals został przekazany obiekt nie należący do klasy Person, zawsze zwrócimy false. Jak sprawdzić, jakiego typu jest obiekt? Zgadza się: używając operatora instanceof.
Oto jak będzie wyglądał nasz nowy kod:
| Kod | Opis |
|---|---|
|
Porównaj referencje Obiekt przekazany — null? Jeśli przekazany obiekt nie jest typu Person |
4. Porównanie dwóch obiektówPerson
Na czym skończyliśmy? Jeśli dotarliśmy do końca metody, to mamy obiekt typu, Persona referencją nie jest null. Następnie konwertujemy go na typ Personi porównujemy wnętrza obu obiektów. To jest nasz scenariusz numer 4.
| Kod | Opis |
|---|---|
|
Porównaj referencje Obiekt przekazany — null? Jeśli przekazany obiekt nie jest Person typu operacji rzutowania |
Jak porównać dwa obiekty Person? Są równe, jeśli mają to samo imię ( name) i wiek ( age). Ostateczny kod będzie wyglądał następująco:
| Kod | Opis |
|---|---|
|
Porównaj referencje Obiekt przekazany — null? Jeśli przekazany obiekt nie jest Person typu operacji rzutowania |
Ale to nie wszystko.
Po pierwsze pole name jest typu String, co oznacza, że pola name muszą być porównane przy użyciu wywołania metody equals.
this.name.equals(person.name)
Po drugie, pole namemoże równie dobrze być sobie równe null: wtedy equalsnie można z niego wywołać metody. Dodatkowa weryfikacja jest wymagana dla null:
this.name != null && this.name.equals(person.name)
Jeśli jednak nazwa jest taka sama nullw obu obiektach Person, nazwy są nadal równe.
Kod czwartego scenariusza może wyglądać następująco:
|
Jeśli wiek nie jest równy, natychmiast . return false Jeśli this.namerówny null, nie ma sensu porównywać przez equals. Tutaj albo drugie pole namejest równe null, albo nie. Porównujemy dwa pola nazwa do equals. |
5. MetodahashCode()
Oprócz metody equals, która dokonuje szczegółowego porównania wszystkich pól obu obiektów, istnieje jeszcze jedna metoda, która może posłużyć do niedokładnego, ale bardzo szybkiego porównania - hashCode().
Wyobraź sobie, że sortujesz alfabetycznie listę tysięcy słów i musisz stale porównywać słowa w parach. A słowa są długie i jest w nich dużo liter. Ogólnie rzecz biorąc, takie porównanie będzie trwało bardzo długo.
Można to jednak przyspieszyć. Załóżmy, że słowa zaczynają się na różne litery: od razu widać, że są różne. Teraz, jeśli zaczynają się od tych samych liter, nie ma gwarancji: w przyszłości słowa mogą okazać się zarówno równe, jak i różne.
Metoda hashCode()działa w podobny sposób. Jeśli zostanie wywołany na obiekcie, zwróci określoną liczbę - odpowiednik pierwszej litery w słowie. Ta liczba ma następujące właściwości:
- Te same obiekty mają zawsze ten sam kod skrótu
- Różne obiekty mogą mieć ten sam kod skrótu lub różne
- Jeśli obiekty mają różne kody skrótu, obiekty są zdecydowanie różne
Dla lepszego zrozumienia przepisujemy te właściwości w odniesieniu do słów:
- Te same słowa mają zawsze tę samą pierwszą literę
- Różne słowa mogą mieć takie same pierwsze litery lub mogą mieć różne.
- Jeśli słowa mają różne pierwsze litery, słowa są zdecydowanie różne
Ostatnia właściwość służy do przyspieszonego porównywania obiektów:
Najpierw obliczane są kody skrótu dla dwóch obiektów. Jeśli te kody skrótu są różne, to obiekty są zdecydowanie różne i nie ma potrzeby ich dalszego porównywania.
Ale jeśli kody skrótu są takie same, nadal musisz porównywać obiekty za pomocą równości.
6. Umowy w kodzie
Zachowanie opisane powyżej musi być zaimplementowane przez wszystkie klasy w Javie. Nie ma możliwości sprawdzenia poprawności porównywania obiektów na poziomie kompilacji.
Wszyscy programiści Javy zgodzili się, że jeśli zamiast domyślnej (z klasy Object) piszą własną implementację metody equals() , to muszą również napisać własną implementację metody hashCode(), aby powyższe zasady zostały zachowane.
Taka umowa nazywana jest umową .
Jeśli dodasz do swojej klasy implementację tylko jednej metody equals()lub tylko hashCode(), rażąco naruszasz umowę (zrywasz umowę). Nie możesz tego zrobić.
Jeśli inni programiści użyją twojego kodu, może on nie działać poprawnie. Ponadto użyjesz kodu, który działa w oparciu o powyższe umowy.
We wszystkich kolekcjach w Javie, szukając elementu w kolekcji, najpierw porównuje się kod skrótu obiektów, a dopiero potem wywołuje metodę equals.
Dlatego jeśli napiszesz swoją klasę, a w niej nową funkcję equals, ale nie napiszesz metody hashCode()ani nie zaimplementujesz jej z błędami, kolekcje mogą nie działać poprawnie z twoimi obiektami.
Na przykład dodałeś obiekt do listy, a następnie szukasz go za pomocą metody contains(), ale kolekcja nie znajduje twojego obiektu.
GO TO FULL VERSION