객체의 주소 값이 달라도 객체의 값이 같으면 같은 객체로 판단하는 것을 동등성
이라고 한다.
즉, Person 타입의 인스턴스 p1, p2가 있을 때 객체가 가지고 있는 값이 같은 경우 동등한 인스턴스
라고 한다.
class Person {
private String name;
private int age;
public Person(String name, int age){ /*생략*/ }
@Override
public boolean equals(Object o) {
//IDE 도움을 받아서 override한 equals 메소드
//equals 메소드에서 사용되는 필드는 hashCode()에서도 사용되어야 한다.
}
}
Person p1 = new Person("Person", 20);
Person p2 = new Person("Person", 20);
System.out.println(p1 == p2); // false
System.out.println(p1.equals(p2)); // true
equals()
메소드를 통해 동등성을 비교하면 true
를 출력한다.equals()
메소드만 재정의하더라도 문제되지 않는다.hashCode()
메소드를 재정의하지 않은 Person
인스턴스를 HashMap의 key로 사용해보자.
HashMap<Person, String> map = new HashMap<>();
Person p1 = new Person("David", 20); // Person 인스턴스 p1 생성
Person p2 = new Person("David", 20); // p1과 동등한 p2 생성
map.put(p1, "David"); // p1을 HashMap의 key로 사용하여 저장
String name = map.get(p2); // p2를 이용하여 get
System.out.println(name);
[출력 결과]
null
put 메소드로 전달된 key 객체의 hashCode()
메소드를 호출하여 hash 값을 얻는다.
만약, hashCode()
메소드가 재정의되어있지 않다면 Object 클래스의 hashCode를 호출할 것이고 이는 단순히 메모리상의 주소 값을 리턴한다.
반환된 해시 값에 해당하는 버킷
에 Entry(k, v)
를 저장한다.
put 메소드와 마찬가지로 get 메소드로 전달된 key 객체의 hashCode()
메소드를 호출하여 해시 값을 얻는다.
반환된 해시 값에 해당하는 버킷
에 찾아가 Entry
가 있는지 확인한다.
hashCode()
메소드를 재정의하지 않았기 때문에 서로 다른 인스턴스 p1과 p2의 hashCode 메소드는 서로 다른 값을 해시 값을 반환한다.HashMap이 버킷에 저장하는 요소는 value가 아닌 Entry(k, v) 객체이다. 하나의 버킷에 여러 Entry 객체들이 저장되어 있을 때 value 값에 대해서 equals() 메소드를 수행해서 동등성을 비교하는 것이 아니다.
자바에서 HashMap과 HashSet은 아주 빈번하게 사용되는 자료구조이다.
지금 당장에는 인스턴스의 동등성만 비교할 것 같지만 요구사항의 변화에 따라 의도하지 않은 부작용을 야기할 수 있다.
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + age;
result = prime * result + ((name == null) ? 0 : name.hashCode());
return result;
}
[출처]
https://www.java67.com/2013/06/how-get-method-of-hashmap-or-hashtable-works-internally.html
https://tecoble.techcourse.co.kr/post/2020-07-29-equals-and-hashCode/