memostack
article thumbnail
블로그를 이전하였습니다. 2023년 11월부터 https://bluemiv.tistory.com/에서 블로그를 운영하려고 합니다. 앞으로 해당 블로그의 댓글은 읽지 못할 수 도 있으니 양해바랍니다.
반응형

Object의 equals()와 hashCode()

equals()

equals()는 보통 동일한 객체인지 확인할 때 사용한다.

  • 항상 그런것은 아님 String의 경우는 문자열이 동일한지 확인할 때 사용

 

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

 

hashCode()

  • native 언어로 작성된 메소드로 구체적인 내부 구현부는 확인하기 어렵지만, 객체의 해시 값을 반환한다고 주석에 명시 되어 있음
  • 즉, 객체의 해시 값을 int 타입으로 반환함
  • HashTable, HashMap, HashSet 등 Hash를 이용해서 데이터를 저장하는 자료구조에 이점을 줌
    • 데이터 저장 위치를 결정하는데 사용됨
    /**
     * Returns a hash code value for the object. This method is
     * supported for the benefit of hash tables such as those provided by
     * {@link java.util.HashMap}.
     ... 중략 ...
     */
    public native int hashCode();

 

equals()와 hashCode()의 관계

  • equals()를 재정의(override)할 때는, hashCode()도 재정의해야 한다. (항상 함께 재정의)
  • equals()의 값이 true이면, hashCode()도 동일한 값을 가져야 함
  • 반대로 equals() 값이 false이면, hashCode()도 다른 값을 가져야 함

출처: https://www.educative.io/edpresso/what-is-a-hash-code-in-java

 

equals()를 재정의해야하는 이유

사람에겐 고유한 주민등록번호를 가지고 있고, 그 값을 id라 했을때 id가 동일하다면, 같은 사람이다.

public class Main {
    public static void main(String[] args) {
        Person p1 = new Person(1, "hong");
        Person p2 = new Person(1, "hong");

        System.out.println(p1.equals(p2)); // false
    }
}

class Person {
    private final int id;
    private final String name;

    public Person (int id, String name) {
        this.id = id;
        this.name = name;
    }
}

하지만, Object의 equals()는 같은 객체인지 확인하는 메소드이기 때문에, 위 예제와 같이 id값이 같아도 p1.equals(p2) 를 했을때, false를 반환한다.

 

그래서, equals()를 재정의하여 id값이 같은 경우, true를 반환하도록 한다.

public class Main {
    public static void main(String[] args) {
        Person p1 = new Person(1, "hong");
        Person p2 = new Person(1, "hong");

        System.out.println(p1.equals(p2)); // true
    }
}

class Person {
    private final int id;
    private final String name;

    public int getId() {
        return this.id;
    }

    public Person (int id, String name) {
        this.id = id;
        this.name = name;
    }

    @Override
    public boolean equals(Object o) {
        if(o == null) {
            return false; // 비교 대상이 null 인 경우, false
        }
        if (o == this) {
            return true; // 나 자신인 경우, true
        }
        if (getClass() != o.getClass()) {
            return false; // 다른 클래스인 경우, false
        }

        Person p = (Person) o;
        return (this.getId() == p.getId()); // id 값이 동일하다면, true
    }
}

 

하지만, equals()만 재정의하는 경우, HashSet과 같이 해시를 이용한 자료구조를 사용할때 문제가 발생한다.

 

hashCode()를 재정의하는 이유

p1과 p2는 동일한 사람이기 때문에 HashSet에 담았을때, 중복제거하여 1개만 있는것을 기대했지만,

실제로는 사이즈가 2개로 다른 객체로 취급한다.

public class Main {
    public static void main(String[] args) {
        Person p1 = new Person(1, "hong");
        Person p2 = new Person(1, "hong");

        Set<Person> personSet = new HashSet<>();
        personSet.add(p1);
        personSet.add(p2);
        System.out.println(personSet.size()); // 2
    }
}
// ...중략...

 

이때, hashCode()를 재정의하여 동일한 사람인 경우, 동일한 hash 값을 반환하도록 한다.

public class Main {
    public static void main(String[] args) {
        Person p1 = new Person(1, "hong");
        Person p2 = new Person(1, "hong");

        Set<Person> personSet = new HashSet<>();
        personSet.add(p1);
        personSet.add(p2);
        System.out.println(personSet.size()); // 1
    }
}

class Person {
    private final int id;
    private final String name;

    public int getId() {
        return this.id;
    }

    public Person (int id, String name) {
        this.id = id;
        this.name = name;
    }

    @Override
    public int hashCode() {
        final int PRIME = 31;
        int result = 1;
        result = PRIME * result + getId();
        return result;
    }

    @Override
    public boolean equals(Object o) {
        // ... 중략 ...
    }

}

 

결론

따라서, equals()hashCode()는 항상 같이 재정의해야함

 

다른 글

2021/03/07 - [Language/JAVA] - Java의 String과 StringBuilder, StringBuffer 비교

 

Java의 String과 StringBuilder, StringBuffer 비교

String String은 불변성( Imutable )을 가진 객체로 + 연산자를 통해 문자열을 생성하는 경우, 새로운 문자열을 반환한다. String greet = "Hello"; System.out.println(greet.hashCode()); greet += " World"; Sy..

memostack.tistory.com

2021/03/07 - [Language/JAVA] - JVM GC(Garbage Collector) 구조

 

JVM GC(Garbage Collector) 정리

GC (Garbage Collector) JVM에는 메모리를 자동으로 관리해주는 특징이 있는데, 이 역할을 Garbage Collector (가비지 콜렉터)이 한다. Stop The World GC에는 stop-the-world 라는 것이 존재하여, 메모리가 관리..

memostack.tistory.com

 

반응형
블로그를 이전하였습니다. 2023년 11월부터 https://bluemiv.tistory.com/에서 블로그를 운영하려고 합니다. 앞으로 해당 블로그의 댓글은 읽지 못할 수 도 있으니 양해바랍니다.
profile

memostack

@bluemiv_mm

포스팅이 좋았다면 "좋아요❤️" 또는 "구독👍🏻" 해주세요!