java 에서 equals 와 hashcode 를 재정의 해야하는 이유

2025. 11. 11. 00:51·JAVA

동등성(equality)과 동일성(identity)

동일성(identity)

  • 자바에서 동일성은 비교되는 두 변수의 값이 같은지를 비교한다.
  • 물리적으로 같으냐를 생각해도 좋을 듯하다.
  • ‘==’ 연산자로 비교를 진행한다.

동등성(equality)

  • 자바에서 동등성은 두 객체의 내용이 같은지를 의미한다.
  • 동일성과 비교해 논리적인 같음을 비교한다.
  • 모든 자바 클래스는 Object 클래스를 상속받는데 Object 의 equals 로 동등성을 비교한다.

class Person{
		private String name;

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

		@Override
		public boolean equals(Object obj) {
			if (this == obj) return true;
			if (obj == null || getClass() != obj.getClass()) return false;
			Person person = (Person) obj;
			return Objects.equals(name, person.name);
		}
}

new Person("hi").equals(new Person("hi")); => 동등함을 보장

eqauls만으로 동등성이 완벽히 보장이 될까

  • 위에서 설명했듯이 동등성은 논리적인 같음을 의미한다.
  • 하지만 eqauls 만 재정의한다고 모든 경우의 동등성을 보장하지 않을 수 있다.

public class Main {
	public static void main(String[] args) {
		HashSet<Person> set  = new HashSet<>();

		for (int i = 0; i < 100; i++) {
			var a = new Person("hi");

			set.add(a);
		}

		System.out.println(set.size());
	}
}
  • Set 자료형은 동등하다면 중복 저장하지 않는 특성을 가졌다.
  • equals 를 재정의한 Person 이 동등함을 보장한다면 객체를 100 번 더한다면 set의 크기는 1이 되어야 한다.
  • 100이 저장됐다. 이유는 Hash 관련 컬랙션의 내부 구현과 관련되어 있다.

HashMap 구현

  • HashMap에 객체를 put 하면 위 방식대로 저장이 이루어진다.
  • 우선 key 객체의 hashCode 값을 기반으로 Map 내부적인 연결리스트가 원소인 배열 크기로 나머지 연산을 통해 배열의 인덱스를 구한다.
  • 배열 원소마다 연결리스트로 관리되며 순환하여 동등한 객체가 있는지 검사한다.
  • 검사 로직은 다음과 같다.

if (e.hash == hash && ((k = e.key) == key || (key != null && key.equals(k))))
  • hash 값이 같고 equals 연산으로 같음을 보장해야 동등하다고 판단한다.
  • HashMap은 동등하다면 value를 덮어씌우고 동등한 key 객체가 없으면 연결리스트 Leaf 에 새로운 노드를 추가하는 구조이다.
  • 따라서 HashSet에 equals를 재정의한 내용이 같은 객체를 100번 추가했을 때 size가 1이 아닌 100이 나온이유가 hash 값이 달라서이다.

추가학습) hashCode를 재정의하지 않는다해도 hash 값이 같을 수 있다.


public class Main {
	public static void main(String[] args) {
		HashSet<Person> set  = new HashSet<>();

		HashMap<String, String> map = new HashMap<>();

		for (int i = 0; i < 1000000; i++) {
			var a = new Person("hi");

			set.add(a);
		}

		System.out.println(set.size());
	}
  • 아직 hashCode 값을 재정의하지 않고 반복 횟수를 키웠다.
  • 1000000 의 크기가 나와야하지 않을까?
  • 이상한 값이 나온 것을 볼 수 있다.
  • 이유는 해시 충돌 문제 때문이다.
  • 따라서 구현에 따라 다음과 같이 Hash 관련 컬렉션이 인식한다.

equals 구현 , hashCode 미구현 => 동등하지 않음 (불규칙적으로 가끔 동등할 수 있음, 예측불가)
equals 미구현 , hashCode 구현 => 동등하지 않음
equals 구현, hashCode 구현 => 동등함

equals 와 hashCode는 같이 재정의하자

  • equals 만 구현하면 두 객체가 동등함을 기본적인 상황에서는 보장할 수 있다.
  • 하지만 Hash 관련 컬렉션이나 hash 관련 연산이 이루어질 때 예측 못할 오류를 발생시킬 수 있다.
  • hash 관련 연산이 없을거 같다고 하더라도 리팩터링이나 구현이 변경하여 예측못한 오류를 발생할 수 있기 때문에 hashCode와 같이 재정의하는 것이 좋다고 생각한다.



'JAVA' 카테고리의 다른 글

깊은복사와 얕은복사란? Cloneable 을 사용하지 말자  (0) 2025.11.24
자바의 제네릭 기초부터 deep dive  (0) 2025.11.24
[java의 병렬 프로그래밍] complete 할 수 있는 Future -CompletableFuture 의 원리와 사용법  (0) 2025.07.30
[java의 병렬 프로그래밍] Thread를 사용하지 말자 - Executor, Executors, ExecutorService 원리 와 사용법  (0) 2025.07.28
[java의 병렬 프로그래밍] JAVA 동기화와 옳은 사용 가이드  (0) 2025.07.17
'JAVA' 카테고리의 다른 글
  • 깊은복사와 얕은복사란? Cloneable 을 사용하지 말자
  • 자바의 제네릭 기초부터 deep dive
  • [java의 병렬 프로그래밍] complete 할 수 있는 Future -CompletableFuture 의 원리와 사용법
  • [java의 병렬 프로그래밍] Thread를 사용하지 말자 - Executor, Executors, ExecutorService 원리 와 사용법
천방지축 개발자
천방지축 개발자
기록용 블로그
    250x250
  • 천방지축 개발자
    KKanging
    천방지축 개발자
  • 전체
    오늘
    어제
    • 분류 전체보기 (127)
      • 백엔드 (32)
        • Spring framework (4)
        • SpringSecurity (6)
        • JPA (4)
        • DB (6)
        • Spring Cloud (2)
        • CI CD (0)
        • 아키텍처 & 패러다임 & 디자인 패턴 (6)
        • 시스템 설계 & 성능 개선 (4)
      • JAVA (10)
        • 언어 (3)
        • JVM (4)
      • cs (57)
        • 운영체제 (8)
        • 컴퓨터네트워크 (6)
        • 자료구조 (15)
        • 알고리즘 (8)
        • http (20)
      • 인공지능 (5)
        • Reinforcement Learning (5)
      • 기타 (9)
        • 백준 (2)
        • python (2)
        • 백준 장학금 (5)
      • 회고 (5)
        • 토덕-리팩터링 (2)
      • 아티클 (0)
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
  • 링크

  • 공지사항

  • 인기 글

  • 태그

    spring
    JVM
    운영체제
    스케줄링
    최대 힙
    HTTP
    완전이진트리
    AVL트리
    강화학습
    힙트리
    자료구조
    프로세스
    엔티티 그래프
    MSA
    posix
    이분탐색이란
    JPA
    SpringSecurity
    python
    연결리스트
    최소힙
    heapq
    백준 장학금
    연결리스트 종류
    jpa n+1 문제
    백준장학금
    점근적 표기법
    멀티프로세서
    알고리즘
    Kruskal
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.4
천방지축 개발자
java 에서 equals 와 hashcode 를 재정의 해야하는 이유
상단으로

티스토리툴바