Java에서는 두 객체를 비교할 때 사용하는 메서드로 equlas()가 있는데 각 차이점을 알아보겠습니다.
1. Object class
설명에 앞서 Object class에 대해 짚고 넘어가겠습니다.
클래스 선언 시 extends 키워드로 상속하지 않는다면 java.lang.Object 클래스를 상속하게 됩니다. 이는 무엇을 의미하느냐
Java의 모든 클래스는 Object 클래스의 Super 클래스거나 sub클래스라는 의미입니다.
Object 클래스에는 필드가 없고 메서드로만 구성되어 있는데, 이 메서드들이 모든 클래스가 Object를 상속하기 때문에 모든 클래스에서 사용이 가능한 것입니다.
Java 공식 문서를 보면 getClass, hashCode, equals, clone, toString .. 등등을 확인해볼 수 있습니다.
2. equals()의 객체비교
공식 문서를 보면 equlas()의 메서드 패러미터를 보면 Object obj 즉 객체임을 확인할 수 있습니다. Object가 최상위 타입이므로 모든 객체는 Object 타입으로 자동 타입변환 될 수 있음을 의미합니다.
여기서 객체를 비교한다는 것은 객체가 저장하고 있는 데이터가 동일함을 의미하는데 예시를 통해 살펴보겠습니다.
public class Solution {
public static void main(String[] args) throws IOException {
System.setIn(new FileInputStream("src/input.txt"));
String str1 = "Hi";
String str2 = "Hi";
String str3 = new String("Hi");
System.out.println(str1 == str2);
System.out.println(str1 == str3);
}
}
// true
// false
코드를 보면 str1,2,3 모두 "Hi"라는 문자열을 가지지만 str3는 new String으로 만든 객체여서 문자열만 같지 서로 다른 객체임을 나타내는 것을 알 수 있습니다. 이는 hashCode에서 설명하겠습니다.
3. hashCode() 객체 해시코드
위의 코드에서 equals가 false를 반환한 이유는 객체의 메모리 번지를 이용해 *해시코드를 만들어 return 했기 때문입니다.
한 번 해시코드를 통해 식별해보겠습니다.
(*해시코드 : 객체의 주소값을 변환하여 생성한 객체의 고유 정수값)
public class Solution {
public static void main(String[] args) throws IOException {
System.setIn(new FileInputStream("src/input.txt"));
String str1 = "Hello";
String str2 = "Hello";
String str3 = new String("Hello");
System.out.println("str1 == str2 ? " + (str1 == str2));
System.out.println("str1 == str3 ? " + (str1 == str3));
System.out.println("str1 hashCode ? " + System.identityHashCode(str1));
System.out.println("str2 hashCode ? " + System.identityHashCode(str2));
System.out.println("str3 hashCode ? " + System.identityHashCode(str3));
}
}
indentityHashCode를 통해 String의 해시코드를 확인해봤습니다. 이 해시코드의 값이 다르다면 다른 객체로 판단하고, 같으면 equals() 메서드로 다시 비교하게됩니다. 즉 hashCode()에서 true를 반환한다 해도 equals() return 값이 다르면 다른 객체가 되는 것을 의미합니다. 또하나 예시를 들어보겠습니다.
class Human {
private int age;
private String name;
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
----------------------------------------------------------------------
public static void main(String[] args){
Human p1 = new Human();
p1.setAge(27);
p1.setName("ROME");
Human p2 = new Human();
p2.setAge(27);
p2.setName("ROME");
System.out.println(p1.equals(p2)); // false
}
위의 결과처럼 HashCode를 비교해서 false를 반환하는 것을 볼수가 있는데, 이를 equals()를 오버라이딩하여 값이 동일한지 아닌지 비교할 수있도록 해보겠습니다.
@Override
public boolean equals(Object obj) {
if (obj == null) {
return false;
}
if (this.getClass() != obj.getClass()) {
return false;
}
if (this == obj) {
System.out.println("Object Same");
return true;
}
Human that = (Human) obj;
if (this.name == null && that.name != null) {
return false;
}
if (this.age == that.age && this.name.equals(that.name)) {
System.out.println("Object Value Same");
return true;
}
return false;
}
// true
이처럼 오버라이딩을 통해 재정의하여 해당 인스턴스들이 갖고있는 값들이 같은 경우 같을 때 이를 같은 인스턴스로 봐야하는 경우에 equals를 오버라이딩하여 사용합니다.
결론적으로 객체의 동등한 비교를 위해 equals()뿐 아니라 hashCode()도 재정의하여 논리적 동등 객체일 경우 동일 해시코드가 return 하도록 해야합니다.
(equals() : 두 객체의 내용이 같은지, hashCode() : 두 객체가 같은 객체인지 확인)
참조
'Skills > Java' 카테고리의 다른 글
Java - 정적 팩토리 메서드를 고려하는 상황 (1) | 2022.10.08 |
---|---|
Java - JDBC (0) | 2022.10.04 |
Java - 바이트 코드 (0) | 2022.09.20 |
Java - JVM & Garbage Collector (0) | 2022.09.16 |
Java - static import (0) | 2022.08.29 |