Java - equals()와 hashCode()

청포도봉봉이·2023년 11월 2일
1

java

목록 보기
1/20
post-thumbnail

개요

equals()와 hashcode() 메소드의 역할과 어떤 상황에서 사용되는지 설명해보자.


정리

equals() 와 ==


Java에서는 equals()==는 차이가 있다.

equals() 메서드는 Object 클래스에 정의된 메서드로, 두 객체가 동등한지를 비교한다. 기본적으로 equals() 메서드는 두 객체의 참조(주소)가 아닌 내부의 값(데이터)을 비교한다. 따라서 두 객체가 동일한 값을 가지고 있으면 equals() 메서드는 true를 반환한다. equals() 메서드는 필요에 따라 클래스마다 재정의(override)하여 동등성을 비교하는 방식을 변경할 수 있다.

반면에 == 연산자는 두 개체의 참조(주소)가 동일한지를 비교한다. 즉, == 연산자는 객체의 실제 값이 아닌 객체의 메모리 주소를 비교한다. 따라서 == 연산자는 두 객체가 정확히 동일한 객체인지를 확인한다.

코드로 살펴본다면

String str1 = "Hello";
String str2 = "Hello";

System.out.println(str1 == str2); // true
System.out.println(str1.equals(str2)); // true

String s1 = new String("hi");
String s2 = new String("hi");

System.out.println(s1 == s2); // false -> 객체의 주소값을 비교하기 떄문
System.out.println(s1.equals(s2)); // true
System.out.println(s1.hashCode());
System.out.println(s2.hashCode());
System.out.println(s1.hashCode() == s2.hashCode()); // false
System.out.println(s1 == s2); // false -> 객체의 주소값을 비교하기 떄문

주소 값을 참조하기 때문에 결과 값이 false인것을 확인할 수 있다.


String 객체에서의 equals(), hashCode()


System.out.println(s1.equals(s2)); // true
System.out.println(s1.hashCode() == s2.hashCode()); // false

String 객체에서의 equals()hashCode()는 아래와 같이

// String.java
public boolean equals(Object anObject) {
if (this == anObject) {
        return true;
}
return (anObject instanceof String aString)
        && (!COMPACT_STRINGS || this.coder == aString.coder)
        && StringLatin1.equals(value, aString.value);
}

public int hashCode() {
        int h = hash;
        if (h == 0 && !hashIsZero) {
                h = isLatin1() ? StringLatin1.hashCode(value)
                                : StringUTF16.hashCode(value);
                if (h == 0) {
                hashIsZero = true;
                } else {
                hash = h;
                }
        }
        return h;
}

재정의하여 사용하기 때문에 값이 같다면 true가 나올 수 있다.


Object에서의 equals(), hashCode()


package day1;

import java.util.Objects;

public class Man {
    String name;

    public Man(String name) {
        this.name = name;
    }
}
Man man1 = new Man("hmmini");
Man man2 = new Man("hmmini");

System.out.println(man1.equals(man2)); //false -> equals 메소드를 재정의해야함
System.out.println(man1.hashCode()); //713338599
System.out.println(man2.hashCode()); //168423058
System.out.println(man1.hashCode() == man2.hashCode()); //false

String 객체처럼 재정의가 안되어 있는 클래스를 살펴보면

// Object.java
public boolean equals(Object obj) {
	return (this == obj);
}

@IntrinsicCandidate
public native int hashCode();
System.out.println(man1.equals(man2)); //false
System.out.println(man1.hashCode() == man2.hashCode()); //false

위와 같이 같은 값이 들어가 있음에도 Man의 equals()는 ==를 사용하여 주소 값을 비교하기 때문에 false라는 결과 값을 얻을 수 있다.

따라서 같은 값이 들어가 있는 객체는 객체의 동등성을 위배해서는 안되고 또한 동일한 객체이므로 동일성을 위해 동일한 해시코드를 반환해야 한다.

따라서 eqauls()hashCode() 메서드를 오버라이딩하여 재정의해야 한다.


Overiding으로 재정의


package day1;

import java.util.Objects;

public class Woman {
    String name;

    public Woman(String name) {
        this.name = name;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Woman person = (Woman) o;
        return Objects.equals(name, person.name);
    }

    @Override
    public int hashCode() {
        return Objects.hash(name);
    }
}

위와 같이 equals()hashCode()를 오버라이딩하여 동등성, 동일성에 위배되지 않도록 재정의해주면

Woman woman1 = new Woman("mini");
Woman woman2 = new Woman("mini");

System.out.println(woman1.equals(woman2)); //true -> equals를 재정의하였음
System.out.println(woman1.hashCode());
System.out.println(woman2.hashCode());
System.out.println(woman1.hashCode() == woman2.hashCode()); //true -> overiding으로 재정의하였음

위와 같이 메서드를 재정의 해주었기 때문에

System.out.println(woman1.equals(woman2)); //true
System.out.println(woman1.hashCode() == woman2.hashCode()); //true

두 객체의 equals()hashCode()에 대한 결과가 true임을 확인 할 수 있다.

profile
서버 백엔드 개발자

0개의 댓글