[Java] hashCode 함수와 equals 함수가 뭐고 그건 언제 쓰는걸까?

이민호·2025년 5월 6일

코테를 대비하기위해서 Collection 프레임워크를 공부하다가,
hashcode와 equals 함수의 재정의에 대해 공부를 하게 되었다.

다들 한번씩 개발 도중에 메소드 오버라이딩 하면서, 이와 같은 창을 본 적이 있을 것이다.

나도 그랬지만 용도가 뭔지 모르고, 무심코 넘겼을것이다.
오늘은 이 메소드에 대해 알아보고 기록해보고자 한다.



🎈이게 뭐임??

hashcode()와 equals() 메소드는 주로 동등비교에 사용된다.

우선 자바에서 두 객체를 비교한다는 것에는
동등성(equality)비교동일성(identity)비교가 있다.



1. 동일성(identity) 비교 (==)

동일성 비교에서는 자료형에 따라 달라지는데,
원시 타입(primitive type)과 참조 타입(reference type)에 따라 그 용도가 달라진다.

int a = 10;
int b = 10;
System.out.println(a == b); // true

원시타입은 단순히 변수가 저장된 메모리에 값 자체를 저장하므로,
==는 곧 값비교가 된다.

참조타입은 변수가 저장된 메모리에 객체의 주소 값을 저장하므로 ==는 주소값 비교한다.
변수 a와 b는 값은 같지만, 엄연히 다른 객체로 간주된다.

String a = new String("hello");
String b = new String("hello");

System.out.println(a == b);   // false   


2. 동등성(equality)비교 (eqauls())

물리적인 객체는 달라도, 값이 같으면 같다고 비교하는 연산이고,
eqauls() 메소드를 사용하여 판단한다.
참조타입에서만 사용한다.

String a = new String("hello");
String b = new String("hello");
System.out.println(a.equals(b));    // true 


Object eqauls()

Object equals() 함수는 기본적으로는 동일성을 비교한다.

하지만 동일성은 충분히 ==로 비교 가능하므로, 우리는 이 함수를 오버라이딩하여 동등성을 비교하는 것으로 바꿔서 사용한다.
그리고 실제로 String Class에서는 이미 자동으로 오버라이딩 되어 있어,

이전 예시에서 보여줬던 것 처럼 동등성 비교가 적용이 되는 것이다.



🎈주로 어디서 사용해?

특히, 이 둘은 Hash기반 Collection 프레임워크에 사용된다고 할 수 있다.

Set Collection은 객체의 저장 순서가 상관없고, 중복이 허용되지 않는 특징을 가진다. 그 중 대표적인 클래스인 hashSet를 살펴보자.

그 전에,
우리가 String 객체를 만든다고 생각을 했을 때

  • String str1 = new String("a");
  • String str2 = new String("a");
    이 둘은 엄연히 다른 "객체"임을 알 것이다.

하지만, hashSet에서는 동일한 객체란 꼭 같은 인스턴스를 의미하지는 않는다.

그것은 hashSet의 동일성 판단 과정 때문인데,


와 같은 과정을 따르고,

hashCode()는 일단 객체의 메모리 주소값을 return하는 함수임을 생각하자.

실제로 Object Class의 코드를 까봐도 알 수 없었다.

하지만,

난 저 flow에서 이상한 점을 발견했다.

hashcode가 같으면 그냥 같은거니까 같은 객체로 생각하면 안되나? 왜 굳이 한번 더 equals()로 비교하는거지???

그에대한 대답은 이 해시코드는 고유값이 아니라는 점이다.



🎃이게 머선소리야?

hashCode값은 객체의 "값"을 기준으로 만들어 지기 때문에, 내용이 같은 객체라면 동일한 해시코드가 나와서 해시 기반 자료구조에서 제대로 동작할 수 있다.

하지만 객체의 값이 달라도 해시같이 같은 경우가 있는데

hashCode는 무한한 객체를 유한한 숫자 공간(int = 약 43억 개) 안에 매핑해야 하기 때문에, 서로 다른 객체가 같은 해시코드를 가질 수도 있다.

이를 해시 충돌이라고 한다. 이 해시충돌이 일어날 수 있기 때문에 한 번더 equals() 함수를 이용해 판단하는 것이다.


결론

따라서 hashCode 함수와 eqauls 함수는 함께 오버라이딩 되어야 한다!!

1. hashCode 함수는 같은 값을 가진 객체는 항상 해시 같은 값이 나오도록 오버라이딩 해야한다.

  • equals()가 true인 두 객체는 반드시 같은 hashCode()를 가져야 한다.

  • 그렇지 않으면 HashMap, HashSet 같은 해시 기반 컬렉션에서 예상치 못한 오류가 발생할 수 있다.

  • hashCode를 적절하게 오버라이딩 하지 않을 때는 아래왜 같은 오류가 발생.

Set<Person> set = new HashSet<>();
set.add(new Person("Alice"));
set.add(new Person("Alice"));

System.out.println(set.size()); //  2 → 중복인데도 둘 다 들어감

2. equals 함수는 동등성 비교로 오버라이딩 해야한다.

  • hashCode 함수만 알맞게 오버라이딩 한 경우에도, equals() 함수에서 같이 같은 객체에 대해서 주소값이 다를 수 있기 때문에(equals()의 기본은 동일성 == 판단이라고 이전에 얘기했다) 다른 객체로 판단할 수 있다.

3. 해시 충돌을 피할 수 없기 때문이다.

profile
효율적으로 살게요.

0개의 댓글