본문 바로가기
Language/Java

[Java]equals()와 hashCode()에 대해서 알아보자(동등성 동일성)

by jaee_ 2021. 8. 29.

이번엔 Object 클래스의 equals()와 hashCode()에 대해서 알아보려 한다.

 

그 전에 제목에 적어놓은 동등성과 동일성의 개념부터 짚고 넘어가자

동등성

객체의 내부값을 비교하는 것을 말한다. 동등성은 equals()로 비교하며 주로 참조자료형을 비교할 때 사용한다.

동일성

객체 인스턴스의 주소값을 비교하는 것을 말한다. 동일성은 == 로 비교하며 기본자료형은 == 연산자를 통해 값 비교가 가능하다.

기본 자료형을 비교할 때 == 연산자를 사용한다. 참조 자료형을 비교할 땐 ==를 사용하면 참조값(메모리 주소)을 비교하기 때문에 객체의 내부값이 같더라도 비교할 수가 없다.

 

Object의 equals()

equals()를 사용하면 객체의 내부값을 비교할 수 있다는 것은 위에서 언급을 했으니 알 수 있다. 기본자료형의 경우 == 을 통해서도 값 비교가 가능하다. 또한 String의 경우에도 constant pool이라는 영역이 존재해서 equals로 값비교가 가능하다.

 

하지만 name과 age를 변수로 가지는 Person이라는 클래스가 존재한다고 했을 때 name이 "Jaee", age가 "27" 인 Person1, Person2 라는 두 객체를 생성한 뒤 값을 비교하면 어떻게 나올까? 아래의 코드로 직접 확인해보자.

// Person class
public class Person {

    private int age;
    private String name;

    public Person() {
    }

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

}       
       
       
// 실행코드       
Person person1 = new Person(27, "Jaee");
Person person2 = new Person(27, "Jaee");\


System.out.println("person1.equals(person2) : " + person1.equals(person2)); // false
System.out.println("person1.hashCode() : " + person1.hashCode()); // 460141958
System.out.println("person2.hashCode() : " + person2.hashCode()); // 1163157884

 

결과값은 false가 나온다. 그 이유는 equals() 메소드는 Object 클래스의 hashCode() 메소드의 결과값인 해시값을 가지고 비교를 하기 때문이다. 위의 코드에서 hashCode()를 실행시켰을 경우의 결과값이 다른 것을 볼 수 있다. 그렇기 때문에 참조자료형의 올바른 동등성 비교를 위해서는 equals()와 hashCode()를 오버라이딩 해줘야 한다. 우선 equas()를 오버라이딩해보자. 

 

public class Person {

    private int age;
    private String name;

    public Person() {
    }

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


    @Override
    public boolean equals(Object o) {
    	// 같은 객체를 참조, 참조값이 동일한 경우 true
        if (this == o) {	
            return true;
        }
        // 비교대상 객체가 null이거나 비교대상의 class가 동일한지 확인 다를경우 false
        if (o == null || getClass() != o.getClass()) {	
            return false;
        }
        Person person = (Person) o;
        // 객체 내부값을 비교하여 리턴
        return age == person.age
            && Objects.equals(name, person.name);
    }

// 실행코드       
Person person1 = new Person(27, "Jaee");
Person person2 = new Person(27, "Jaee");\


System.out.println("person1.equals(person2) : " + person1.equals(person2)); // true
System.out.println("person1.hashCode() : " + person1.hashCode()); // 460141958
System.out.println("person2.hashCode() : " + person2.hashCode()); // 1163157884

equals()를 오버라이딩 시키고 실행코드를 실행시키니 equals()로 비교한 값이 true로 나왔다. 하지만 hashCode()의 값은 여전히 다르다. 그렇기 때문에 hashCode()도 오버라이딩을 해줘야 한다.

 

Object의 hashCode()

위에서 언급했듯이 해시코드란 객체를 식별할 수 있는 고유값을 말한다.  equals()만 오버라이딩을 해주었다고 객체의 내부값이 동일해지는 것이 아니다. 같은 객체임을 나타내기 위해선 hashCode()도 반드시 오버라이딩을 해주어야 한다. 

 

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

Person클래스에 위의 hashCode()를 오버라이딩 해주었다.

Person person1 = new Person(27, "Jaee");
Person person2 = new Person(27, "Jaee");

System.out.println("person1.equals(person2) : " + person1.equals(person2)); // true
System.out.println("person1.hashCode() : " + person1.hashCode()); // 71331461
System.out.println("person2.hashCode() : " + person2.hashCode()); // 71331461

equals()와 hashCode()를 모두 오버라이딩 해주고나니 두 객체를 비교했을 때 hashCode()도 동일하게 가지고, equals()도 true로 나온다. 비로소 두 객체가 같은 값을 가진다고 인식하게 되는 것이다. 

 

댓글