객체가 가지고 있는 속성과 타입이 같다면 동일한 객체로 비교하고 싶다.
예를 들어서, 지난 체스 만드는 미션에서 체스말에서 체스말들을 그런식으로 비교하고 싶을 수 있다
동일성(==) 비교는 객체가 참조하고 있는 주소값을 비교한다.
그래서 속성과 타입이 같아도 참조값이 다르면 다른 객체로 구분한다.
이를 해결할 수 있는 건, 동등성 비교(equals)이다.
그런데 equals 도 내부를 보면 파라미터를 Object를 받고 그 Object와 메서드를 부른 객체를 동일성(==) 비교한다.
public boolean equals(Object obj) {
return (this == obj);
}
그래서 다음과 같이 확인해보면 둘다 동일한 결과를 가져다준다.
public class Main {
int x;
int y;
public Main(int x, int y) {
this.x = x;
this.y = y;
}
public static void main(String[] args) {
Main main = new Main(1, 2);
Main main2 = new Main(1, 2);
Main main3 = main;
System.out.println(main == main2); // 동일성을 비교하니까 false
System.out.println(main == main3); // 동일성을 비교하고 둘다 같은 객체를 참조하므로 true
System.out.println(main2 == main3); // main3 은 main이 참조하는것과 같으므로 false
System.out.println();
System.out.println(main.equals(main2)); // 위와 마찬가지로 false
System.out.println(main.equals(main3)); // 마찬가지로 true
System.out.println(main2.equals(main3)); // 마찬가지로 false
}
}
false
true
false
false
true
false
근데 equals 를 재정의하면 속성과 타입이 같을때 같은 객체로 비교할 수 있도록 할 수 있다.
예를 들어서, String 은 그런식으로 내부적으로 equals가 재정의되어있다
일단 먼저 String 으로 비교해보자
String a = "a";
String b = "a";
System.out.println(a.equals(b));
true
String도 똑같이 객체이다. 근데 이런 다른 결과를 가져다 주는 것은 equals가 재정의 되어있기 때문이다.
참고로 String은 동일성(==) 비교를 해도 true. String의 특성때문이다.
JVM에서는 String을 조금 특별히 관리하기 때문에, 객체이지만 new연산자가 아니라 리터럴("")을 이용해서 String 을 생성 할 수있다. 이때 JVM은 객체의 영역인 heap 영역이 아니라, constant pool 영역으로 찾아간다. 그리고 constant pool 영역에 이전에 같은 값을 가지고 있는 String 객체가 있다면, 그 객체의 주소값을 반환하여 참조하도록 한다.
이전 포스팅: String 클래스 & Constant Pool
실제로 확인해보면 다음과 같이 재정의 되어있다
public boolean equals(Object anObject) {
if (this == anObject) {
return true;
}
if (anObject instanceof String) {
String aString = (String)anObject;
if (!COMPACT_STRINGS || this.coder == aString.coder) {
return StringLatin1.equals(value, aString.value);
}
}
return false;
}
체스 미션에 속성이 같으면 같은 객체로 인식하도록 equals 를 재정의해본다면 다음과 같이 만들 수 있다.
@Override
public boolean equals(final Object obj) {
if (obj instanceof Piece) {
final Piece piece = (Piece) obj;
return color == piece.color && type == piece.type;
}
if (this == obj) {
return true;
}
return false;
}
질문
AssertJ 이용해서 테스트하면 재정의만 하고 사용하진 않았다고 생각했는데 막상assertThat().isEqualTo()
를 사용해보면 이미 사용하고 있음 Why?