동일성과 동등성 Value Object

Kyu·2021년 2월 27일
0

Java 공부기록

목록 보기
34/40

객체가 가지고 있는 속성과 타입이 같다면 동일한 객체로 비교하고 싶다.

예를 들어서, 지난 체스 만드는 미션에서 체스말에서 체스말들을 그런식으로 비교하고 싶을 수 있다

동일성(==) 비교는 객체가 참조하고 있는 주소값을 비교한다.
그래서 속성과 타입이 같아도 참조값이 다르면 다른 객체로 구분한다.

이를 해결할 수 있는 건, 동등성 비교(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?

참고
이전 포스트: [자바] Value Object
VO(Value Ojbect)란 무엇일까?

profile
TIL 남기는 공간입니다

0개의 댓글