Porównaj dwa obiekty z operatorem .equals () i ==

84

Zbudowałem klasę z jednym Stringpolem. Następnie utworzyłem dwa obiekty i muszę je porównać za pomocą ==operatora i .equals()też. Oto, co zrobiłem:

public class MyClass {

    String a;

    public MyClass(String ab) {
        a = ab;
    }

    public boolean equals(Object object2) {
        if(a == object2) { 
            return true;
        }
        else return false;
    }

    public boolean equals2(Object object2) {
        if(a.equals(object2)) {
            return true;
        }
        else return false;
    }



    public static void main(String[] args) {

        MyClass object1 = new MyClass("test");
        MyClass object2 = new MyClass("test");

        object1.equals(object2);
        System.out.println(object1.equals(object2));

        object1.equals2(object2);
        System.out.println(object1.equals2(object2));
    }


}

Po kompilacji w rezultacie pokazuje dwa razy fałsz. Dlaczego jest fałszem, jeśli dwa obiekty mają te same pola - „test”?

Fastkowy
źródło
7
Przy okazji, patrząc na equalsi equals2: za każdym razem, gdy masz coś w formie if(a) { return true; } else { return false; }, prawdopodobnie powinieneś po prostu napisać return a.
yshavit
@yshavit Masz na myśli zmianę z boolean na String?
Fastkowy
4
nie, twój kod pyta, czy wartość logiczna jest prawdą, i zwraca, truejeśli tak jest , a jeśli falsenie. Na przykład if(a.equals(object2)) { return true; } else return falsemoże być return a.equals(object2).
yshavit
1
możliwy duplikat Jak porównać ciągi znaków w Javie?
bjb568

Odpowiedzi:

142

==porównuje odniesienia do obiektów, sprawdza, czy dwa operandy wskazują ten sam obiekt (nie równoważne obiekty, ten sam obiekt).

Jeśli chcesz porównać ciągi (aby zobaczyć, czy zawierają te same znaki), musisz porównać ciągi za pomocą equals.

W twoim przypadku, jeśli dwa wystąpienia MyClassnaprawdę są uważane za równe, jeśli ciągi pasują do siebie, to:

public boolean equals(Object object2) {
    return object2 instanceof MyClass && a.equals(((MyClass)object2).a);
}

... ale zwykle, jeśli definiujesz klasę, równoważność polega na czymś więcej niż na równoważności pojedynczego pola ( aw tym przypadku).


Uwaga dodatkowa: jeśli nadpisujesz equals, prawie zawsze musisz go zastąpić hashCode. Jak jest napisane w equalsJavaDoc :

Zauważ, że generalnie konieczne jest przesłonięcie hashCodemetody za każdym razem, gdy ta metoda jest nadpisywana, aby zachować ogólny kontrakt dla hashCodemetody, który stanowi, że równe obiekty muszą mieć równe kody skrótu.

TJ Crowder
źródło
@TJ In == porównuje odniesienia do obiektów, aby rozwinąć, czy to oznacza == porównuje hashcode dwóch obiektów?
Narendra Jaggi
@NarendraJaggi - Nie, oznacza to, że maszyna JVM sprawdza, czy oba operandy odnoszą się do tego samego obiektu. Sposób , w jaki to robi, zależy od JVM, ale nie ma powodu, aby sądzić, że użyje do tego kodu skrótu.
TJ Crowder
19

Powinieneś zastąpić równa się

 public boolean equals (Object obj) {
     if (this==obj) return true;
     if (this == null) return false;
     if (this.getClass() != obj.getClass()) return false;
     // Class name is Employ & have lastname
     Employe emp = (Employee) obj ;
     return this.lastname.equals(emp.getlastname());
 }
user5119219
źródło
2
Jest to prawdopodobnie najlepsza odpowiedź, jednak możesz chcieć użyć this.equals (obj) zamiast (this == null) dla typów innych niż pierwotne
goonerify
10
Twierdzę, że if (this == null)sprawa i tak jest niepotrzebna; wywołanie nullObject.equals(whatever)spowoduje zgłoszenie wyjątku wskaźnika o wartości null, więc możemy bezpiecznie założyć, że thisnie ma wartości null w żadnej z metod Javy, które możemy napisać.
Maura
1
zakończy się niepowodzeniem, gdy this ma lastnamewartość null i nie spełnia poprzednich warunków.
Ahmed Raaj,
5

Wygląda na equals2to, że dzwoni equals, więc da te same wyniki.

Hew Wolff
źródło
OP wywołuje equalsmetodę String, aktóra jest członkiem klasy. equals2nie dzwoniequals
Yigit Alparslan
5

Funkcja nadpisywania równa się () jest nieprawidłowa. Obiekt „a” jest instancją klasy String, a „object2” jest instancją klasy MyClass . Są to różne klasy, więc odpowiedź brzmi „fałsz”.

Jesús Talavera Portocarrero
źródło
5

Najlepszym sposobem porównania 2 obiektów jest przekonwertowanie ich na ciągi json i porównanie ciągów, co jest najłatwiejszym rozwiązaniem w przypadku skomplikowanych zagnieżdżonych obiektów, pól i / lub obiektów zawierających tablice.

próba:

import com.google.gson.Gson;


Object a = // ...;
Object b = //...;
String objectString1 = new Gson().toJson(a);
String objectString2 = new Gson().toJson(b); 

if(objectString1.equals(objectString2)){
    //do this
}
JoeG
źródło
9
Chciałbym to nazwać: przesada.
Rolf ツ
@Rolf ツ Dlaczego Twoim zdaniem to przesada? Szukałem rozwiązania tego problemu i jest to najłatwiejsze rozwiązanie, jakie do tej pory znalazłem. Wszelkie lepsze sugestie są mile widziane.
m5seppal
3
Ponieważ w Javie można porównać obiekty bez tworzenia Gsonobiektu, a następnie wywoływania toJson. Tworzenie Gsonobiektu i wywoływanie logiki potrzebnej do konwersji rzeczywistego obiektu na flat String( toJson) jest zbędnym narzutem. Możesz porównać obiekty bez uprzedniej konwersji obiektów na ciągi Json (co jest również szybsze).
Rolf ツ
3

Twoja equals2()metoda zawsze zwróci to samo co equals()!!

Twój kod z moimi komentarzami:

public boolean equals2(Object object2) {  // equals2 method
    if(a.equals(object2)) { // if equals() method returns true
        return true; // return true
    }
    else return false; // if equals() method returns false, also return false
}
jlordo
źródło
5
Po prostureturn a.equals(object2);
mojuba
2

Instrukcje a == object2i a.equals(object2)oba zawsze będą zwracane, falseponieważ ajest a stringwhile object2jest wystąpieniemMyClass

ashish.al
źródło
2

Twoja realizacja musi lubić:

public boolean equals2(Object object2) {
    if(a.equals(object2.a)) {
        return true;
    }
    else return false;
}

W tej implementacji obie metody będą działać.

Azhar Khan
źródło
2

Jeśli nie potrzebujesz dostosowywać domyślnej funkcji toString (), innym sposobem jest nadpisanie metody toString (), która zwraca wszystkie atrybuty do porównania. następnie porównaj wyjście toString () dwóch obiektów. Wygenerowałem metodę toString () za pomocą IDE IntelliJ IDEA, która zawiera nazwę klasy w ciągu.

public class Greeting {
private String greeting;

@Override
public boolean equals(Object obj) {
    if (this == obj) return true;
    return this.toString().equals(obj.toString());
}

@Override
public String toString() {
    return "Greeting{" +
            "greeting='" + greeting + '\'' +
            '}';
}
}
Qinjie
źródło
2

Operator „==” zwraca prawdę tylko wtedy, gdy dwa odwołania wskazują na ten sam obiekt w pamięci. Z drugiej strony metoda equals () zwraca wartość true na podstawie zawartości obiektu.

Przykład:

String personalLoan = new String("cheap personal loans");
String homeLoan = new String("cheap personal loans");

//since two strings are different object result should be false
boolean result = personalLoan == homeLoan;
System.out.println("Comparing two strings with == operator: " + result);

//since strings contains same content , equals() should return true
result = personalLoan.equals(homeLoan);
System.out.println("Comparing two Strings with same content using equals method: " + result);

homeLoan = personalLoan;
//since both homeLoan and personalLoan reference variable are pointing to same object
//"==" should return true
result = (personalLoan == homeLoan);
System.out.println("Comparing two reference pointing to same String with == operator: " + result);

Wynik: Porównanie dwóch ciągów z operatorem ==: false Porównywanie dwóch ciągów o tej samej zawartości przy użyciu metody equals: true Porównanie dwóch odwołań wskazujących na ten sam ciąg z operatorem ==: prawda

Więcej informacji można również uzyskać pod linkiem: http://javarevisited.blogspot.in/2012/12/difference-between-equals-method-and-equality-operator-java.html?m=1

Madhan
źródło
2

Twoja klasa może zaimplementować interfejs porównywalny, aby osiągnąć tę samą funkcjonalność. Twoja klasa powinna implementować metodę compareTo () zadeklarowaną w interfejsie.

public class MyClass implements Comparable<MyClass>{

    String a;

    public MyClass(String ab){
        a = ab;
    }

    // returns an int not a boolean
    public int compareTo(MyClass someMyClass){ 

        /* The String class implements a compareTo method, returning a 0 
           if the two strings are identical, instead of a boolean.
           Since 'a' is a string, it has the compareTo method which we call
           in MyClass's compareTo method.
        */

        return this.a.compareTo(someMyClass.a);

    }

    public static void main(String[] args){

        MyClass object1 = new MyClass("test");
        MyClass object2 = new MyClass("test");

        if(object1.compareTo(object2) == 0){
            System.out.println("true");
        }
        else{
            System.out.println("false");
        }
    }
}
tf3
źródło
1

zwracany typ object.equals jest już logiczny. nie ma potrzeby owijania go w metodę z gałęziami. więc jeśli chcesz porównać 2 obiekty, po prostu je porównaj:

boolean b = objectA.equals(objectB);

b jest już prawdą lub fałszem.

Kpt. Mroczny
źródło
1

Kiedy używamy ==, odniesienie obiektu jest porównywane, a nie rzeczywiste obiekty. Musimy nadpisać metodę equals, aby porównać obiekty Java.

Niektóre dodatkowe informacje C ++ ma przeciążenie operatora, a Java nie zapewnia przeciążenia operatora. Inne możliwości w java to implementacja interfejsu Compare, który definiuje metodę compareTo.

Interfejs komparatora jest również używany do porównywania dwóch obiektów

umesh atada
źródło
4
Weź pod uwagę, że Twoja odpowiedź nie dodaje niczego, czego nie powiedziano prawie 2 lata temu.
Hot Licks
1

Tutaj wynik będzie fałszywy, fałszywy, ponieważ w pierwszej instrukcji sopln próbujesz porównać zmienną typu string typu Myclass z innym typem MyClass i pozwoli to, ponieważ oba są typem Object i użyłeś operatora "==", który sprawdzi wartość zmiennej odniesienia przechowującej aktualną pamięć, a nie rzeczywiste elementy w pamięci. W drugim sopln jest tak samo, jak ponownie wywołujesz a.equals (object2), gdzie a jest zmienną wewnątrz object1. Daj mi znać swoje ustalenia w tej sprawie.

Bidyadhar
źródło
2
Witamy w stackoverflow bidyadhar. Pytanie jest datowane na 14.11.2012 i otrzymało już dobrą odpowiedź (zatwierdzona przez OP). Ten, który otrzymałeś, jest poprawny, ale nie dodaje przydatnych informacji. Sugeruję, abyś przeczytał zasady, zanim cokolwiek zrobisz
Nikaido
-3

W poniższym kodzie wywołujesz metodę overriden .equals ().

public boolean equals2 (Object object2) {if (a.equals (object2)) {// tutaj wywołujesz metodę overriden, dlatego dwa razy otrzymujesz false. powrót prawda; } else zwraca false; }

Baran
źródło
1
Nie, a.equalsto metoda stringów, nigdzie nie jest zastępowana.
Tarec