본문 바로가기

JAVA

[JAVA] equals(), hashCode() 재정의(동등성과 동일성)

728x90

개요

각 메서드를 보기 앞서 개념을 먼저 살펴보자.


동등성

동등하다는 것은 논리적인 지위가 같다는 것을 뜻한다.
그리고 이 논리적인 지위는 개발자가 결정한다.

아래 Person 클래스로 예를 들어보자.

class Person{
	String name;
	String personality;
}


두 Person이 있다고 할 때 이름만 같을 경우 두 Person을 같다고 판단할지,
성격도 같아야 두 Person이 같다고 판단할지 여기에 대한 기준은 개발자가 정한다.

이렇게 논리적인 기준이 같은지 판단하는 것을 동등성 비교라고 한다.
그리고 java 메서드로는 equals()를 사용한다.


동일성

동일하다는 것은 모든 것이 일치한다는 것을 뜻한다.
'모든 것'에는 내부 값, 주소 등이 포함된다.

java에서는 == 연산자로 비교하며,
같은 값을 가지는 같은 주소의 객체인지 판단하는 것을 동일성 비교라고 한다.

앞서 언급한 대로 동등성을 비교하는 데 있어 java에서는 equals() 메서드를 사용한다.
그리고 그 논리적인 기준을 정할 수 있도록 equals() 메서드를 오버라이딩할 수 있다.

equals()

논리적인 기준을 정하고 객체를 비교해 보자.
위와는 조금 다른 Person 클래스를 만들었다.
Person.java

public class Person {  
  
    private final String name;  
    private final Integer age;  
  
    public Person(String name, Integer age) {  
        this.name = name;  
        this.age = age;  
    }
}

 

먼저 똑같은 값을 가지는 두 Person 객체를 생성하고 비교해 보자.

@Test  
void 두_Person_객체의_값이_동일하면_equals_메서드가_true를_반환한다() {  
    // given  
    Person choi1 = new Person("choi", 10);  
    Person choi2 = new Person("choi", 10);  
  
    // when & then  
    assertEquals(choi1, choi2);  
}

테스트 결과는 위와 같다.

기본적으로 객체의 동등성 비교는 해당 객체의 주소값으로 비교된다는 것을 알 수 있다.
즉, 기본적인 동등성 비교는 동일성 비교와 똑같이 수행된다.

이제 equals() 객체를 오버라이딩 해서 테스트가 성공할 수 있도록 해보자.

public class Person {  
  
    private final String name;  
    private final Integer age;  
  
    public Person(String name, Integer age) {  
        this.name = name;  
        this.age = age;  
    }  
  
    @Override  
    public boolean equals(Object object) {  
        if (object == this) {  
            return true;  
        }  
  
        if (!(object instanceof Person person)) {  
            return false;  
        }  
  
        return name.equals(person.name)  
            && age.equals(person.age);  
    }  
}


equals 내부를 보자.

 

if (object == this) {  
            return true;  
        }

 

1. 만약 두 객체가 동일성을 가진다면 당연히 동등성도 가질 것이다.

if (!(object instanceof Person person)) {  
            return false;  
        }

 

2. 두 객체의 타입이 다르다면 당연히 동등할 수 없다.

return name.equals(person.name)  
            && age.equals(person.age);

 

3. 여기서 논리적인 기준을 정한 것이다.
Person의 내부 값 모두가 동일해야 두 Person 객체가 동일한 것이라는 논리적인 기준을 정했다.

이제 테스트가 성공하는 것을 볼 수 있다.


Hashcode()

hashCode란 각 객체가 가지는 고유 정수값을 말한다.
이 hashCode는 HashSet, HashMap 등 컬렉션을 사용할 때 이용된다.

위 Person 클래스를 HashSet으로 테스트해보려고 한다.

@Test  
void 동등한_두_Person_객체를_HashSet에_추가했을때_해당_set의_크기는_1이어야한다() {  
    // given  
    Person choi1 = new Person("choi", 10);  
    Person choi2 = new Person("choi", 10);  
    Set<Person> persons= new HashSet<>();  
  
    // when  
    persons.add(choi1);  
    persons.add(choi2);  
  
    // then  
    assertEquals(1,persons.size());  
}

하지만 HashSet에선 두 객체가 다른 객체로 취급되기 때문에 크기가 2이다.

여기서 두 객체가 같은 hash code를 가지려면 
hashCode() 메서드를 오버라이딩해서 같은 값을 이용해 hash 작업을 할 수 있도록 해야 한다.

@Override  
public int hashCode() {  
    return Objects.hash(name,age);  
}


name과 age를 이용해 hash 작업을 하도록 했다.
때문에 name과 age의 값이 같다면 같은 hash code를 가질 것이다.

그리고 기대대로 테스트를 통과한 것을 볼 수 있다.

 

728x90

'JAVA' 카테고리의 다른 글

[JAVA] 상속과 조합  (1) 2023.11.08
[JAVA] VO(Value Object), 원시값 포장  (0) 2023.10.28
[JAVA] JVM 메모리 영역  (0) 2023.06.13
[JAVA] 자바는 항상 Call-by-value로 동작한다?  (0) 2023.06.02