[Java] equals()와 hashCode() 메서드 알아보기
equals와 hashCode란 무엇인가?
자바의 부모 객체 Object 클래스 위에는 equals()와 hashCode() 메서드가 선언되어 있다.
1. equals()란?
★ 동일성(equality), 동등성(identity)
동일한 객체가 메모리 상에서 띄워져 있는 경우는 서로 다른 메모리에 있으므로 동일한 객체가 아니다.
하지만 같은 값을 지니므로 equals 메서드를 사용해 동등성을 나타내주는 것이다. 값으로 객체를 비교하도록 equals 메서드를 오버라이딩하는 것이다.
여기서 의미하는 동일성(equality)과 동등성(identity)은 다른 개념이다. 동일한 값을 갖는 문자열을 2개 생성했을 때, 동등성을 비교하는 equals 메서드를 호출하면 true가 나오지만, 동일성을 비교하면 서로 다른 메모리에 할당되기 때문에 false가 출력된다. 변수를 비교할 때는 다른 값이 출력된다.
String s1 = new String("Test");
String s2 = new String("Test");
System.out.println(s1 == s2); // false
System.out.println(s1.equals(s2)); // true
✔️ == 연산 (동일성)
== 연산은 '동일하다', 즉 값을 비교하는 연산이다.
Member 객체를 생성하여 object 클래스의 equals() 메서드를 오버라이딩 하여 객체의 동등성을 정의하고 있다.
public class Member {
private String name;
public Member(String name) {
this.name = name;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Member member = (Member) o;
return Objects.equals(name, member.name);
}
}
Member member1 = new Member("name");
Member member2 = new Member("name");
System.out.println("member 1 == member2 : " + member1.equals(member2));
System.out.println("member1 hashcode : " + member1.hashCode());
System.out.println("member2 hashcode : " + member2.hashCode());
출력값은 equals() 메서드를 호출하여 name 필드의 값의 동등성을 비교할 때 값이 같으므로 true가 출력된다.
하지만 hashCode() 메서드를 호출하면 각 객체의 해시 코드 값은 같지 않다. 따라서 hashCode() 또한 재정의 해야 함을 알 수 있다.
객체가 생성될 때 고유한 해시코드가 생성된다. 이 해시코드를 hashCode라는 공통 메서드를 호출해 가져올 수 있다. equals를 오버라이딩하여 해시코드를 비교한다.
2. hashCode란?
객체를 식별하는 하나의 고유 정숫값을 말한다.
해시코드 메서드는 자바에서 객체의 해시 값을 반환하는 메서드이다. 해시 기반의 컬렉션에 저장하거나 사용하고, HashMap, HashSet, HashTable 등이 있다.
equals() 메서드를 이용하여 객체의 동등성(equality)을 정의했다면, 반드시 hashCode() 메서드도 함께 재정의 해야 한다.
따라서 다음과 같이 Member 객체에 해시코드를 재정의하면, 같은 해시 값이 출력됨을 알 수 있다.
@Override
public int hashCode() {
return Objects.hash(name);
}
그럼 equals()와 hashCode()를 같이 override 해야하는 이유는?
You must override hashCode() in every class that overrides equals().
Failure to do so will result in a violation of the general contract for Object.hashCode(), which will prevent your class from functioning properly in conjunction with all hash-based collections, including HashMap, HashSet, and Hashtable.
From Effective Java, by Joshua Bloch
equals()를 오버라이드하는 클래스에서는 반드시 hashCode()도 오버라이드 해야 합니다. 그렇지 않으면 Object.hashCode()의 일반 규약을 위반하게 되는데, 이는 HashMap, HashSet, Hashtable 등 해시 기반 컬렉션과 함께 해당 클래스가 제대로 동작하지 못하게 할 수 있습니다.
일반 규약에 따라 equals()가 true를 반환하는 두 객체는 같은 hashCode() 값을 반환해야 한다. 그렇지 않으면, 동일한 두 객체가 각각 hashCode() 값을 다르게 저장하여 해시 컬렉션이 동작할 때 문제가 발생할 수 있기 때문이다. 잘못 오버라이딩 했을 때 hash 컬렉션의 성능이 저하될 수 있다.
hashCode 규약
- equals 비교에 사용되는 정보가 변경되지 않았다면, 애플리케이션이 실행되는 동안 객체의 hashCode 메서드는 몇 번을 호출해도 항상 같은 값을 반환해야 한다.
- equals(Object)가 두 객체를 같다고 판단했으면, 두 객체의 hashCode는 같은 값을 반환해야 한다.
- 하지만 equals(Object)가 두 객체를 다르다고 판단했더라도, 두 객체의 hashCode 값은 같을 수 있다. (해시 충돌, Hash Collisions)
hashCode를 잘못 오버라이딩하면 HashMap 등 hash 컬렉션의 성능이 떨어질 수 있다. 위 두 번째 조약에서 문제가 발생한다.
참고
https://jiwondev.tistory.com/113
.equals와 .hashCode()는 항상 함께 오버라이딩해야한다.
Object 메서드에 있는 .hashCode() 메서드는 해당 객체의 주소값을 이용하여 만든 객체만의 고유한 정수 값을 가진다. equals()를 오버라이딩 할 때에는 반드시 hashCode()도 동일한 결과를 내도록 함께 오
jiwondev.tistory.com
https://mangkyu.tistory.com/101
[Java] equals와 hashCode 함수
1. equals와 hashCode란? equals와 hashCode는 모든 Java 객체의 부모 객체인 Object 클래스에 정의되어 있다. 그렇기 때문에 Java의 모든 객체는 Object 클래스에 정의된 equals와 hashCode 함수를 상속받고 있다. [ e
mangkyu.tistory.com
https://www.baeldung.com/java-equals-hashcode-contracts