블로그를 이전하였습니다. 2023년 11월부터 https://bluemiv.github.io/에서 블로그를 운영하려고 합니다. 앞으로 해당 블로그의 댓글은 읽지 못할 수 도 있으니 양해바랍니다.
반응형
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()
도 다른 값을 가져야 함
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 비교
2021/03/07 - [Language/JAVA] - JVM GC(Garbage Collector) 구조
반응형
'Language > JAVA' 카테고리의 다른 글
Java - Collection과 Map의 종류(List, Set, Map) (4) | 2021.03.09 |
---|---|
Java - HashMap과 Hashtable의 차이 (0) | 2021.03.08 |
Java - String Pool에 대해서 (0) | 2021.03.07 |
Java의 String과 StringBuilder, StringBuffer 비교 (0) | 2021.03.07 |
JVM GC 동작 순서와 GC 종류(Serial / Parallel / CMS / G1 GC ) (0) | 2021.03.07 |