Object 는 동등성 비교를 위한 equals() 메서드를 제공한다.
자바는 두 객체가 같다라는 표현을 2가지로 분리해서 제공한다.
단어 정리
"동일"은 완전히 같음을 의미한다. 반면 "동등"은 같은 가치나 수준을 의미하지만 그 형태나 외관 등이 완전히 같지는 않을 수 있다.
쉽게 이야기해서 동일성은 물리적으로 같은 메모리에 있는 객체 인스턴스인지 참조값을 확인하는 것이고, 동등성은 논리적으로 같은지 확인하는 것이다.
동일성은 자바 머신 기준이고 메모리의 참조가 기준이므로 물리적이다. 반면 동등성은 보통 사람이 생각하는 논리적인 기준에 맞추어 비교한다.
예를 들어 같은 회원 번호를 가진 회원 객체가 2개 있다고 가정해보자.
User a = new User("id-100"); // 참조 x001
User b = new User("id-100"); // 참조 x002
이 경우 물리적으로 다른 메모리에 있는 다른 객체이지만, 회원 번호를 기준으로 생각해보면 논리적으로는 같은 회원으로 볼 수 있다.
(주민등록번호가 같다고 가정해도 된다.)
따라서 동일성은 다르지만, 동등성은 같다.
문자의 경우도 마찬가지이다.
String s1 = "hello";
String s2 = "hello";
이 경우 물리적으로는 각각의 "hello" 문자열이 다른 메모리에 존재할 수 있지만, 논리적으로는 같은 "hello"라는 문자열이다.
(사실 이 경우 자바가 같은 메모리를 사용할 수 있도록 최적화 한다. 이 부분은 뒤에서 다룬다.)
예제를 통해서 동일성과 동등성을 비교해보자.
package lang.object.equals;
public class UserV1 {
private String id;
public UserV1(String id) {
this.id = id;
}
}
package lang.object.equals;
public class EqualsMainV1 {
public static void main(String[] args) {
UserV1 user1 = new UserV1("user");
UserV1 user2 = new UserV1("user");
// user1과 user2는 다른 객체이다.
System.out.println(user1 == user2);
// user1과 user2는 다른 객체이다.
System.out.println(user1.equals(user2));
}
}
false
false
둘 다 같은 결과가 나옵니다.
초기에 equals 는 아래와 같습니다.
public boolean equals(Object obj) {
return (this == obj);
}
UserV2 는 id(고객번호)가 같으면 논리적으로 같은 객체로 정의하겠다.
package lang.object.equals;
public class UserV2 {
private String id;
public UserV2(String id) {
this.id = id;
}
// equals() 메서드를 오버라이딩한다.
@Override
public boolean equals(Object obj) {
UserV2 user = (UserV2) obj;
return this.id.equals(user.id);
}
}
package lang.object.equals;
public class EqualsMainV2 {
public static void main(String[] args) {
UserV2 user1 = new UserV2("user");
UserV2 user2 = new UserV2("user");
// user1과 user2는 다른 객체이다.
System.out.println(user1 == user2);
// user1과 user2는 같은 객체이다.
System.out.println(user1.equals(user2));
}
}
false
true
앞서 UserV2 에서 구현한 equals() 는 이해를 돕기 위해 매우 간단히 만든 버전이고, 실제로 정확하게 동작하려면 다음과 같이 구현해야한다. 정확한 equals() 메서드를 구현하는 것은 생각보다 쉽지 않다.
IntelliJ를 포함한 대부분의 IDE는 정확한 equals() 코드를 자동으로 만들어준다.
Window: Alt + Insert
Mac: options + N
package lang.object.equals;
import java.util.Objects;
public class UserV2 {
private String id;
public UserV2(String id) {
this.id = id;
}
// equals() 메서드를 오버라이딩한다.
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
UserV2 userV2 = (UserV2) o;
return Objects.equals(id, userV2.id);
}
}
equals() 메서드를 구현할 때 지켜야 하는 규칙
실무에서는 대부분 IDE가 만들어주는 equals() 를 사용하므로, 이 규칙을 외우기 보다는 대략 이렇구나 정도로 한번 읽어보고 넘어가면 충분하다.
정리