Kurs Java

Metoda equals

Mówi się, że jeśli tylko ktoś dotknął programowania w Javie, to na pewno słyszał o metodzie equals. Pewnie dużo w tym przesady, ale fakt faktem, że jest to jedna z najważniejszych metod, które trzeba znać jeśli chcemy się mianować programistami tego języka.

Porównanie obiektów za pomocą ==

Słowo equals z angielskiego znaczy "równa się" i w tym samym kontekście jest używane w Javie. Metoda o tej nazwie służy do porównywania obiektów. Zanim jednak dojdziemy do jej omawiania, zobaczmy jeszcze inny sposób porównywania.

Podstawowym porównaniem w Javie jest użycie dwóch znaków równości występujących po sobie, na przykład:
MovieItem movieItem = new MovieItem(1, "Avatar");
MovieItem nextMovieItem = new MovieItem(1, "Avatar");

if(movieItem == nextMovieItem) {
    System.out.println("Ten sam obiekt");
}
Użycie znaku podwójnej równości powoduje wykonanie sprawdzenia czy obiekty wskazują na to samo miejsce w pamięci, a więc czy jest to de facto jeden i ten sam obiekt. Oczywiście tworząc dwie różne instancje obiektów (za pomocą słowa new) mamy tak naprawdę zarezerwowane dwa różne miejsca w pamięci, zatem porównanie zwróci false i tekst w bloku if nie zostanie wydrukowany.

Metoda equals

Podobne porównanie możemy wykonać za pomocą metody equals:
MovieItem movieItem = new MovieItem(1, "Avatar");
MovieItem nextMovieItem = new MovieItem(1, "Avatar");

if(movieItem.equals(nextMovieItem)) {
    System.out.println("Ten sam obiekt");
}
Czy teraz otrzymamy inny rezultat? Okazuje się, że nie. Powyższe porównanie zostanie wykonane w dokładnie ten sam sposób co wyżej i w tym przypadku również otrzymamy false. Wynika to z implementacji metody equals w klasie Object, która tak naprawdę wykorzystuje porównanie ==, o którym pisaliśmy wyżej :
public boolean equals(Object obj) {
    return (this == obj);
}
Co nam zatem to daje, że każdy obiekt w Javie posiada tę metodę?

Przesłanianie metody equals

Metoda equals - ze względu na to, że jest typową metodą klasy Object - może zostać przesłonięta w naszej klasie MovieItem. W ten sposób możemy sami dostarczyć algorytm porównujący:
class MovieItem {
    
    private int id;
    
    private String name;
    
    MovieItem(int id, String name) {
        this.name = name;
        this.id = id;
    }
    
    @Override
    public boolean equals(Object o) {
    
        if(!(o instanceof MovieItem)) {
            return false;
        }
    
        MovieItem other = (MovieItem) o;
        
        return id == other.id;
    }
}
Metoda przyjmuje parametr w postaci obiektu klasy Object. Oznacza to, że musimy być bardzo ostrożni w trakcie jej implementacji i dlatego pierwszą rzeczą, którą sprawdzamy jest to, czy podany tutaj obiekt jest instancją klasy MovieItem. Wiadomo, że jeśli prześlemy do metody zupełnie inny obiekt, na przykład obiekt klasy User, to w takiej sytuacji obiekt "użytkownik" będzie zdecydowanie czymś innym niż obiekt "film" i dlatego też w takiej sytuacji zwracamy false.

Skoro już wiemy, że mamy do czynienia z obiektem klasy MovieItem, to kolejnym krokiem jest zrzutowanie go w dół na obiekt klasy MovieItem. Rzutowanie w dół, to w skrócie przekształcenie obiektu bazowego na obiekt bardziej doprecyzowany (dziedziczący z klasy albo implementujący dany interfejs), dzięki czemu uzyskujemy dostęp do jego metod i pól. Klasa MovieItem dziedziczy z klasy Object, a więc możemy to zrobić. Tym samym w kolejnej linii uzyskujemy dostęp do pól klasy MovieItem.

Na koniec porównujemy ze sobą wartość liczbową zapisaną w polu id bieżącego obiektu z wartością liczbową id obiektu przesłanego do metody. Przy tak zaimplementowanej metodzie equals poniższy warunek zwróci true i na konsoli zobaczymy wskazany wydruk:
MovieItem movieItem = new MovieItem(1, "Avatar");
MovieItem nextMovieItem = new MovieItem(1, "Avatar");

if(movieItem.equals(nextMovieItem)) {
    System.out.println("Ten sam obiekt");
}
Stanie się tak dlatego, gdyż po pierwsze obiekt nextMovieItem jest typu MovieItem, a po drugie wartości w polach id w obu instancjach są sobie równe (1 jest równe 1). Porównujemy tutaj wartości liczbowe, a że id nie jest obiektem to zasada == opisana na początku rozdziału (mówiąca o tych samych lub różnych miejscach w pamięci) nie znajduje tutaj zastosowania. Operator == działa inaczej w przypadku obiektów, a inaczej w przypadku typów prostych.

Ciekawostka. Co się dzieje gdy użyjemy operatora porównania == do porównania obiektów liczbowych, na przykład typu Integer? Odpowiedź na to pytanie znajdziemy przeglądając kod metody equals zaimplementowanej w samej klasie Integer. Okazuje się, że tam najpierw zwracana jest wartość liczbowa typu int, a dopiero później ta wartość jest porównywana z wartością z drugiego obiektu typu Integer. Tak więc, mimo że na początku mamy do czynienia z obiektami, to ostatecznie i tak porównywane są nie miejsca w pamięci, a konkretne wartości liczbowe.

public boolean equals(Object obj) {
    if (obj instanceof Integer) {
        return value == ((Integer) obj).intValue();
    }
    return false;
}      
Linki
https://www.leepoint.net/data/expressions/22compareobjects.html
https://www.tutorialspoint.com/What-are-up-casting-and-down-casting-in-Java
Masz pytanie dotyczące tego rozdziału? Zadaj je nam!
Masz pytanie dotyczące prezentowanego materiału?
Coś jest dla Ciebie niejasne i Twoje wątpliwości przeszkadzają Ci w pełnym zrozumieniu treści?
Napisz do nas maila, a my chętnie znajdziemy odpowiednie rozwiązanie.
Najciekawsze pytania wraz z odpowiedziami będziemy publikować pod rozdziałem.
Nie czekaj. Naucz się programować jeszcze lepiej.
kursjava@javappa.com

Stale się rozwijamy, a więc bądź na bieżąco!
Na ten adres będziemy przesyłać informacje o ważniejszych aktualizacjach, a także o nowych materiałach pojawiających się na stronie.
Polub nas na Facebooku:
Nasi partnerzy:
Javappa to również profesjonalne usługi programistyczne oparte o technologie JAVA. Jeśli chesz nawiązać z nami kontakt w celu uzyskania doradztwa bądź stworzenia aplikacji webowej powinieneś poznać nasze doświadczenia.
Kliknij O nas .