Java

[Java]Object 클래스의 equals 메서드

DevStory 2022. 9. 3.

Object 클래스의 equals 메서드

Java에 모든 클래스는 최상위 클래스인 Object에서 파생됩니다. 따라서, Object 클래스에 구현된 메서드를 사용할 수 있으며, 그중 equals() 메서드를 사용하여 두 객체가 동등한지 확인할 수 있습니다.

 

equals() 메서드는 객체의 실제 데이터가 아닌 참조 값을 기반으로 두 객체를 비교합니다. 두 객체가 동일한 참조 값을 가지면, true를 반환하고 그렇지 않으면 false를 반환합니다.


equals 메서드 사용 방법

Object 클래스에 존재하는 equals() 메서드 구문은 다음과 같습니다.

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

 

다음 예제는 개발자가 정의한 Person 클래스의 객체를 equals() 메서드를 사용하여 비교합니다.

public static void main(String args[]) {
  Person person1 = new Person();
  Person person2 = new Person();

  System.out.println(person1.equals(person2));
  System.out.println("person1의 hashCode: " + person1.hashCode());
  System.out.println("person2의 hashCode: " + person2.hashCode());
}

[실행 결과]

false
person1의 hashCode: 1118140819
person2의 hashCode: 1975012498

person1과 person2는 둘 다 기본 생성자 함수로 생성되었지만, 참조 값이 다르므로 equals() 메서드는 false를 반환합니다.

 

실제로 두 객체가 다른 참조 값을 가지고 있는지 확인하기 위해 hashCode() 메서드를 사용해보았습니다. hashCode() 메서드는 객체의 참조 값을 해시 코드로 변환하는데, 두 객체가 동일한 참조 값이 아니므로 다른 해시 코드를 반환합니다.

 

다음 예제는 person1 객체를 person2에 할당 후 equals() 메서드와 hashCode() 메서드를 호출합니다.

public static void main(String args[]) {
  Person person1 = new Person();
  Person person2 = person1;

  System.out.println(person1.equals(person2));
  System.out.println("person1의 hashCode: " + person1.hashCode());
  System.out.println("person2의 hashCode: " + person2.hashCode());
}

 [실행 결과]

true
person1의 hashCode: 1118140819
person2의 hashCode: 1118140819

person1을 person2에 할당하면 동일한 참조 값을 가지므로 equals() 메서드는 true를 반환하고 hashCode() 메서드는 동일한 해시 코드를 반환합니다.

 

하지만, = 연산자를 사용하여 객체를 다른 객체를 할당하면, 동일한 참조 값을 가지므로 몇 가지 문제가 발생합니다.

 

다음 예제는 = 연산자를 사용하여 person1을 persone2에 할당 후 person2의 Age 필드 값을 변경합니다.

public static void main(String args[]) {
  Person person1 = new Person("둘리", 10);
  Person person2 = person1;

  System.out.println("[변경 전]");
  System.out.println("person1.getAge(): " + person1.getAge());
  System.out.println("person2.getAge(): " + person2.getAge());
  System.out.println("person1.equals(person2): " + person1.equals(person2));

  person2.setAge(50);

  System.out.println("\n[변경 후]");
  System.out.println("person1.getAge(): " + person1.getAge());
  System.out.println("person2.getAge(): " + person2.getAge());
  System.out.println("person1.equals(person2): " + person1.equals(person2));
}

[실행 결과]

[변경 전]
person1.getAge(): 10
person2.getAge(): 10
person1.equals(person2): true

[변경 후]
person1.getAge(): 50
person2.getAge(): 50
person1.equals(person2): true

두 객체가 동일한 참조 값을 가지므로 eqauls() 메서드는 true를 반환하지만, person2의 Age 필드를 변경하면, person1의 필드 값은 보존되지 않습니다. 

 

따라서, 참조 값이 아닌 필드 값을 비교하도록 equals() 메서드를 재정의해야 합니다.

반응형

equals 메서드 재정의

위 예제에서 설명했듯이 equasl() 메서드는 참조 값을 기반으로 두 객체를 비교하며, 두 객체의 참조 값이 동일한 경우 발생하는 문제에 대해 알아보았습니다.

 

두 객체를 정확하게 비교하려면, equals() 메서드를 다음과 순서대로 재정의합니다.

 

[equals() 메서드 재정의 순서]

순서 1. 두 객체가 동일한 참조 값을 가지는지 확인합니다. 둘 다 동일한 참조 값을 가지는 경우 데이터도 동일하므로 true를 반환하도록 합니다.

순서 2. 매개변수로 전달받은 객체가 null이거나 두 객체가 동일한 타입이 아니라면, false를 반환하도록 합니다.

순서 3. 매개변수로 전달받은 매개변수를 현재 클래스 타입으로 변환합니다.

순서 4. 모든 필드의 값을 비교합니다. 기본 타입이라면 == 연산자를 사용하고 참조 타입인 경우 Objects 클래스의 equals() 메서드를 사용할 수 있습니다.

 

다음 소스 코드는 equals() 메서드가 재정의된 Person 클래스입니다.

public class Person {
  private String Name;
  private Integer Age;

  @Override
  public int hashCode() {
    return Objects.hash(Name, Age);
  }

  public Person(String name, Integer age) {
    Name = name;
    Age = age;
  }

  public String getName() {
    return Name;
  }

  public void setName(String name) {
    Name = name;
  }

  public Integer getAge() {
    return Age;
  }

  public void setAge(Integer age) {
    Age = age;
  }

  @Override
  public boolean equals(Object o) {
    // 순서 1. 동일한 참조 값인지 비교
    if (this == o) return true;
    // 순서 2. null 또는 동일한 클래스인지 비교
    if (o == null || getClass() != o.getClass()) return false;
    // 순서 3. 타입 변환
    Person person = (Person) o;
    // 순서 4. 필드 비교
    return Objects.equals(Name, person.Name) && Objects.equals(Age, person.Age);
  }
}

만약, Eclips, IntelliJ와 같은 개발 툴을 사용한다면, equals() 메서드를 손쉽게 재정의할 수 있습니다.

 

다음 사진은 IntelliJ에서 equals() 메서드를 재정의하는 방법입니다. 

 

순서 1. 클래스 파일에서 마우스 우클릭 후 Generate... 를 선택합니다.

순서 2. equals() and hashCode()를 클릭하여 원하는 필드의 값을 비교하도록 재정의할 수 있습니다.

다음 예제는 eqausl() 메서드가 재정의된  Person 클래스의 두 객체를 equals() 메서드를 사용하여 비교합니다.

public static void main(String args[]) {
  Person person1 = new Person("둘리", 10);
  Person person2 = new Person("둘리", 10);

  System.out.println(person1.equals(person2));
  System.out.println("person1.hashCode(): " + person1.hashCode());
  System.out.println("person2.hashCode(): " + person2.hashCode());
}

[실행 결과]

true
person1.hashCode(): 1118140819
person2.hashCode(): 1975012498

두 객체의 참조 값은 다르지만, 재정의된 equals() 메서드는 Person 클래스의 필드 값을 비교하므로 true를 반환합니다.


equals 메서드 이해하기

equals() 메서드를 제대로 사용하기 전에 다음 내용을 이해할 필요가 있습니다.

 

1. 기본 타입에서는 equals() 메서드를 사용할 수 없습니다.

 

2. null은 equals() 메서드를 호출할 수 없습니다.

null로 할당된 객체에서 equals() 메서드를 호출하면, 컴파일 에러는 발생하지 않습니다.

 

하지만, 소스 코드를 실행하면 런타임 에러인 NullPointerException이 발생합니다.

public static void main(String args[]) {
  Person person = null;

  System.out.println(person.equals("ABC"));
}

[에러 내용]

 

3. 매개변수가 null인 경우 false를 반환합니다.

public static void main(String args[]) {
  Person person = new Person("둘리", 20);

  System.out.println(person.equals(null));
}

[실행 결과]

false
반응형

댓글