회원가입

equals() - 동일성과 동등성

Beany 2024-12-01

ChatGPT 요약

자바에서 동일성과 동등성을 구분하는 방법에 대해 설명한 블로그 포스트이다. 동일성은 두 객체가 동일한 메모리 참조를 가지는지 확인하는 것이고, 동등성은 논리적으로 같은지 확인한다. equals() 메서드로 동등성을 비교할 수 있으며, 구현 시 반사성, 대칭성, 추이성, 일관성, null 비교 등의 규칙을 따라야 한다. IDE가 자동으로 equals() 코드를 생성해주므로 규칙을 외울 필요는 없다. 또한, 동일성과 비교가 필요한 경우에만 equals()를 재정의하고, hashCode()와 함께 사용하는 것이 일반적이다.

equals() - 동일성과 동등성


Object 는 동등성 비교를 위한 equals() 메서드를 제공한다.

 

자바는 두 객체가 같다라는 표현을 2가지로 분리해서 제공한다.

  • 동일성(Identity): == 연산자를 사용해서 두 객체의 참조가 동일한 객체를 가리키고 있는지 확인.
  • 동등성(Equality): equals() 메서드를 사용하여 두 객체가 논리적으로 동등한지 확인.

 

단어 정리

"동일"은 완전히 같음을 의미한다. 반면 "동등"은 같은 가치나 수준을 의미하지만 그 형태나 외관 등이 완전히 같지는 않을 수 있다.

쉽게 이야기해서 동일성은 물리적으로 같은 메모리에 있는 객체 인스턴스인지 참조값을 확인하는 것이고, 동등성은 논리적으로 같은지 확인하는 것이다.

동일성은 자바 머신 기준이고 메모리의 참조가 기준이므로 물리적이다. 반면 동등성은 보통 사람이 생각하는 논리적인 기준에 맞추어 비교한다.

예를 들어 같은 회원 번호를 가진 회원 객체가 2개 있다고 가정해보자.

User a = new User("id-100"); // 참조 x001
User b = new User("id-100"); // 참조 x002

이 경우 물리적으로 다른 메모리에 있는 다른 객체이지만, 회원 번호를 기준으로 생각해보면 논리적으로는 같은 회원으로 볼 수 있다.
(주민등록번호가 같다고 가정해도 된다.)

따라서 동일성은 다르지만, 동등성은 같다.

 

문자의 경우도 마찬가지이다.

String s1 = "hello";
String s2 = "hello";

이 경우 물리적으로는 각각의 "hello" 문자열이 다른 메모리에 존재할 수 있지만, 논리적으로는 같은 "hello"라는 문자열이다.
(사실 이 경우 자바가 같은 메모리를 사용할 수 있도록 최적화 한다. 이 부분은 뒤에서 다룬다.)

 

예제를 통해서 동일성동등성을 비교해보자.

package lang.object.equals;

public class UserV1 {
    private String id;

    public UserV1(String id) {
        this.id = id;
    }
}
package lang.object.equals;

public class EqualsMainV1 {
    public static void main(String[] args) {
        UserV1 user1 = new UserV1("user");
        UserV1 user2 = new UserV1("user");

        // user1과 user2는 다른 객체이다.
        System.out.println(user1 == user2);

        // user1과 user2는 다른 객체이다.
        System.out.println(user1.equals(user2));
    }
}
false
false

둘 다 같은 결과가 나옵니다.

초기에 equals 는 아래와 같습니다.

public boolean equals(Object obj) {
    return (this == obj);
}

 

 

equals() - 구현


UserV2 예제

UserV2id(고객번호)가 같으면 논리적으로 같은 객체로 정의하겠다.

package lang.object.equals;


public class UserV2 {
    private String id;

    public UserV2(String id) {
        this.id = id;
    }

    // equals() 메서드를 오버라이딩한다.
    @Override
    public boolean equals(Object obj) {
        UserV2 user = (UserV2) obj;
        return this.id.equals(user.id);
    }
}
package lang.object.equals;

public class EqualsMainV2 {
    public static void main(String[] args) {
        UserV2 user1 = new UserV2("user");
        UserV2 user2 = new UserV2("user");

        // user1과 user2는 다른 객체이다.
        System.out.println(user1 == user2);

        // user1과 user2는 같은 객체이다.
        System.out.println(user1.equals(user2));
    }
}
false
true

 

 

정확한 equals() 구현

앞서 UserV2 에서 구현한 equals() 는 이해를 돕기 위해 매우 간단히 만든 버전이고, 실제로 정확하게 동작하려면 다음과 같이 구현해야한다. 정확한 equals() 메서드를 구현하는 것은 생각보다 쉽지 않다.

IntelliJ를 포함한 대부분의 IDE는 정확한 equals() 코드를 자동으로 만들어준다.

Window: Alt + Insert
Mac: options + N

package lang.object.equals;


import java.util.Objects;

public class UserV2 {
    private String id;

    public UserV2(String id) {
        this.id = id;
    }

    // equals() 메서드를 오버라이딩한다.
    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;

        UserV2 userV2 = (UserV2) o;

        return Objects.equals(id, userV2.id);
    }
}

equals() 메서드를 구현할 때 지켜야 하는 규칙

  • 반사성(Reflexivity): 객체는 자기 자신과 동등해야 한다. (x.equals(x) 는 항상 true)
  • 대칭성(Symmetry): 두 객체가 서로에 대해 동일하다고 판단하면, 이는 양방향으로 동일해야 한다. (x.equals(y) 가 true 이면 y.equals(x) 도 true)
  • 추이성(Transitivity): 만약 한 객체가 두 번째 객체와 동일하고, 두 번째 객체가 세번째 객체와 동일하다면, 첫번째 객체는 세번째 객체와도 동일해야 한다.
  • 일관성(Consistency): 두 객체의 상태가 변경되지 않는 한, equals() 메서드는 항상 동일한 값을 반환해야 한다.
  • null에 대한 비교: 모든 객체는 null 과 비교했을 때 false 를 반환해야 한다.

실무에서는 대부분 IDE가 만들어주는 equals() 를 사용하므로, 이 규칙을 외우기 보다는 대략 이렇구나 정도로 한번 읽어보고 넘어가면 충분하다.

 

정리

  • 참고로 동일성비교가 항상 필요한 것은 아니다. 동일성 비교가 필요한 경우에만 equals() 를 재정의하면 된다.
  • equals()hashCode() 는 보통 함께 사용된다. 이 부분은 뒤에 컬렉션 프레임워크에서 자세히 설명한다.
0 0
JAVA
이 공간은 개인 공부를 통해 얻은 정보를 체계적으로 정리하고 공유하는 곳입니다. 학습한 내용, 발견한 지식, 그리고 문제 해결 방법 등을 기록하여 나만의 학습 자료를 구축하고, 필요할 때 쉽게 참고할 수 있는 유용한 자원으로 활용할 수 있도록 합니다.
Yesterday: 456
Today: 45