이번엔 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로 나온다. 비로소 두 객체가 같은 값을 가진다고 인식하게 되는 것이다.
'Language > Java' 카테고리의 다른 글
[Java]Serializable(직렬화)란? (0) | 2021.09.05 |
---|---|
[Java] 불변객체(Immutable Object)에 대해 알아보자 (0) | 2021.08.29 |
[Java] ConcurrentHashMap에 대해 알아보자 (1) | 2021.08.28 |
[Java] String literal 과 new String() 의 차이 (0) | 2021.08.22 |
[Java] final 을 알아보자 (0) | 2021.08.22 |
댓글