WEB(BE)/Spring & Spring Boot

JAVA 값 객체의 동등 비교 ('==' 과 equals() 의 차이)

2025. 3. 8. 18:35
목차
  1. GPT 가 알려준 것
  2. 코드로 확인하기
  3. '연산자 오버로딩'과 '오버라이딩 vs 오버로딩'
  4. 결론
반응형

개발하다가 코드 리뷰를 받으면서 들었던 의문점

엔티티 필드에 값 객체가 존재하고, 외부에서 값 객체가 주어질 때, 해당 값 객체의 값과 엔티티가 갖고있는 값 객체의 값이 같은지 판별해야 하는 메서드를 작성할 일이 생겼다.

 

나는 단순하게 값 객체의 필드를 하나 하나 꺼내서 비교하는 메서드를 그냥 작성했는데, 리뷰로는 `equals()` 메서드를 사용하면 된다는 리뷰를 받았다.

 

코드를 작성할 땐 막연히 `equals()를 사용하면 참조비교하겠지?` 정도로만 생각해서 하나씩 세부 필드를 꺼내서 비교하는 코드를 작성했는데, 그 차이점을 직접 비교해보려고 한다.

 

GPT 가 알려준 것

GPT는 값 객체를 비교할 때 equals 메서드를 오버라이딩 하는 것을 추천하고 있다.

구글링 해봤을 때도 다른 블로그들이 모두 비슷하게 말하고 있었다.

 

 

 

기본적으로 equals 메서드는 Object 의 구현을 따라 동일성을 판별한다고 한다.

동일성은 정말 두 객체가 '동일한 객체인지' 판별하는 것으로, 객체의 교유 해시값을 비교한다.

따라서 만약 equals 메서드의 호출 결과가 true 라면 두 객체의 해시코드 값은 같다.

 

 

자바 공식문서를 보면 정말 그렇다고 한다.

 

 

코드로 확인하기

@Embeddable
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@AllArgsConstructor
public static class Semester {
    private Integer year;
    private SemesterType type;

    public static Semester of(Integer year, SemesterType type) {
        return new Semester(year, type);
    }
}

public enum SemesterType {
    FIRST, SECOND
}

 

위와 같은 값 객체를 만들었다.

혹시 jpa 의 @Embeddable 어노테이션이 비교에 영향을 줄까 싶어 함께 사용했는데, 영향은 따로 주지 않았다.

 

@Test
void testObject() {
    Semester semester1 = new Semester(2024, SemesterType.FIRST);
    Semester semester2 = new Semester(2024, SemesterType.FIRST);

    Assertions.assertThat(semester1.equals(semester2)).isTrue();
}

 

그리고 테스트 코드를 작성했다.

내가 원하는 것은 값이 같다면 객체가 달라도 괜찮은 '동등성' 비교이다.

 

 

테스트는 실패한다.

따라서 기본적으로 equals() 메서드는 객체의 '동일성' 을 판별하는 메서드임을 알 수 있다.

그래서 GPT는 equals() 메서드를 오버라이딩 하라고 한 것이다.

 

@Test
void testObject2() {
    Semester semester1 = new Semester(2024, SemesterType.FIRST);
    Semester semester2 = new Semester(2024, SemesterType.FIRST);

    Assertions.assertThat(semester1 == semester2).isTrue();
}

 

 

이번엔 == 연산자를 사용해서 비교해보았다.

객체에 대해 == 연산자를 사용한 비교를 적용하니 인텔리제이에서 경고문구와 함께 equals() 메서드를 사용하라고 했다.

실행결과는 False 가 나오면서 테스트가 역시 실패했다.

즉, equals() 와 == 연산자 모두 객체에 대해서는 해시코드를 비교하는 '동일성' 비교를 수행한다.

 

그렇다면 '동등성' 비교를 위해서 값을 하나하나 비교하는 메서드를 오버라이딩 해야 할까?

다행히 롬복의 @EqualsAndHashCode 어노테이션을 이용하면 간단하게 해결할 수 있었다.

그리고 equals() 메서드를 오버라이딩 할 때는 객체의 해시값을 계산하는 hashcode() 메서드 역시 함께 오버라이딩 하는 것을 권장하고 있는데, 이 역시 함께 해결된다.

 

 

equals() 메서드 API 문서를 보면 hashCode 메서드도 함께 오버라이딩할 것을 권고하고 있다.

 

@Embeddable
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@EqualsAndHashCode
@AllArgsConstructor
public static class Semester {
    private Integer year;
    private SemesterType type;

    public static Semester of(Integer year, SemesterType type) {
        return new Semester(year, type);
    }
}

 

이렇게 롬복 어노테이션을 통해 equals 메서드를 오버라이딩 하였다.

 

 

기존의 equals 메서드를 사용한 비교 테스트가 통과하는 것을 알 수 있다.

하지만 여전히 == 연산자를 사용한 비교 테스트는 실패한다.

== 연산자는 자바의 기본 연산자로서 그 동작 자체가 이미 객체의 해시값 비교로 이루어져 있어 오버라이딩에 영향을 받지 않기 때문이다.

 

그래서 누군가 equals() 메서드와 == 연산자의 차이를 묻는다면 '기본적으로 두 기능의 동작은 같지만, equals 메서드는 오버라이딩하여 그 동작을 재정의할 수 있는 반면, == 연산자는 재정의할 수 없다' 고 말하면 될 것 같다.

 

'연산자 오버로딩'과 '오버라이딩 vs 오버로딩'

그런데 여기까지 왔더니 다시 떠오른 의문점 하나

c++은 기본 연산자 역시 '연산자 재정의' 가 가능한데, 과연 자바도 가능할까?

 

 

 

그리고 여기에서 나온김에 항상 헷갈리는 개념을 다시 정리하자면.

연산자 재정의는 연산자 '오버로딩' 이라고 한다.

 

오버라이딩 = 부모 클래스의 동작을 자식 클래스에서 재정의 하는 것 (상속 개념과 연관)

오버로딩 = 하나의 클래스에서 같은 이름의 메서드를 다른 형태로 여러 개 정의하는 것 (상속 개념과 무관)

 

그렇다면 왜 연산자는 오버로딩인가?

내가 이해한 것은 c++ 에서 + 연산이 자바와 같이 기본 Object 클래스에 구현되어 있는데, 이를 재정의하고 하는 것이 아니라, 애초부터 객체에 대해서는 + 연산이 존재하지 않았는데, 연산자 정의를 통해서 신규로 생성하며 확장하는 느낌이기 때문에 오버로딩이라고 부른다고 이해했다.

 


결론

equals(), == 연산 모두 기본적으로는 객체의 해시값을 비교해서 '동일성' 을 체크한다.

다만 equals() 메서드를 오버라이딩 해서 '동등성' 을 체크하도록 변경할 수 있으며, 이 변경은 == 연산에는 영향을 주지 않는다.

반응형
저작자표시 비영리 변경금지

'WEB(BE) > Spring & Spring Boot' 카테고리의 다른 글

[Swagger] Failed to load API definition (403, 500, NoSuchMethodError)  (1) 2025.01.22
[Spring Boot] application.yml 데이터베이스 연결 정보 입력  (0) 2025.01.06
[Spring Boot] profile 개념과 profile 분리  (0) 2025.01.04
  1. GPT 가 알려준 것
  2. 코드로 확인하기
  3. '연산자 오버로딩'과 '오버라이딩 vs 오버로딩'
  4. 결론
'WEB(BE)/Spring & Spring Boot' 카테고리의 다른 글
  • [Swagger] Failed to load API definition (403, 500, NoSuchMethodError)
  • [Spring Boot] application.yml 데이터베이스 연결 정보 입력
  • [Spring Boot] profile 개념과 profile 분리
에버듀
에버듀
개발은 좋은데 뭘로 개발할까
에버듀
Blog. 에버듀
에버듀
전체
오늘
어제
  • 분류 전체보기 (585) N
    • 개인 프로젝트 (43)
      • [2020] 카카오톡 봇 (9)
      • [2021] 코드악보 공유APP (22)
      • [2022] 유튜브 뮤직 클론코딩 (9)
      • 간단한 프로젝트 (3)
    • 팀 프로젝트 (22)
      • [2020] 인공지능 숫자야구 (4)
      • [2022] OSAM 온라인 해커톤 (10)
      • [2024] GDSC 프로젝트 트랙 (6)
      • [2025] 큰소리 웹 페이지 (2)
    • 알고리즘 (PS) (107)
      • BOJ (101)
      • Programmers (5)
      • 알고리즘 이모저모 (1)
    • CS (312)
      • 자료구조 (19)
      • 어셈블리 (41)
      • 멀티미디어응용수학 (7)
      • 컴퓨터 구조 (29)
      • 알고리즘 분석 (4)
      • 컴퓨터 네트워크 (38)
      • 프로그래밍언어론 (15)
      • HCI 윈도우즈프로그래밍 (26)
      • 기초데이터베이스 (29)
      • 운영체제 (23)
      • 오토마타 (24)
      • 문제해결기법 (11)
      • 블록체인 (22)
      • 소프트웨어공학 (12)
      • 기계학습심화 (12)
    • 자기계발 (35)
      • 동아리 (7)
      • 자격증 (2)
      • 코딩테스트, 대회 (8)
      • 생각 정리 (17)
      • 머니 스터디 (1)
    • WEB(BE) (5)
      • express.js (1)
      • flask (0)
      • Spring & Spring Boot (4)
    • WEB(FE) (2)
      • html, css, js (1)
      • React.js (1)
    • Tool & Language (6)
      • Edit Plus (1)
      • Git (1)
      • Python3 (2)
      • Java (2)
    • Infra (12)
      • AWS (1)
      • Oracle Cloud (8)
      • Firebase (2)
      • Network (1)
    • Android (18)
      • Java (6)
      • Flutter (12)
    • Window (2)
      • Visual Studio 없이 WPF (1)
      • MFC (1)
    • 독서 (12)
      • Inside Javascript (7)
      • Database Internals (4)
      • 한 글 후기 (1)
    • 인턴 (8)
      • 델파이 (7)
      • Oracle (1)

인기 글

최근 댓글

최근 글

hELLO · Designed By 정상우.v4.1.4
에버듀
JAVA 값 객체의 동등 비교 ('==' 과 equals() 의 차이)
상단으로

티스토리툴바

개인정보

  • 티스토리 홈
  • 포럼
  • 로그인

단축키

내 블로그

내 블로그 - 관리자 홈 전환
Q
Q
새 글 쓰기
W
W

블로그 게시글

글 수정 (권한 있는 경우)
E
E
댓글 영역으로 이동
C
C

모든 영역

이 페이지의 URL 복사
S
S
맨 위로 이동
T
T
티스토리 홈 이동
H
H
단축키 안내
Shift + /
⇧ + /

* 단축키는 한글/영문 대소문자로 이용 가능하며, 티스토리 기본 도메인에서만 동작합니다.