Spring, CS 공부 내용 9

김정용·2025년 2월 3일

기술면접 공부

목록 보기
9/15
post-thumbnail

동일성과 동등성

동일성, 동등성 이름은 비슷해보이는데 무슨뜻일까?

자바에서는 동일성과 동등성으로 객체를 비교한다.

equals()라는 메소드와 == 라는 연산자를 통해서 구분할 수 있다.

equals() vs ==

둘다 A와 B가 같은지를 비교하는 메소드와 연산자 같다.

어떤 차이가 존재할까?

equals() 메소드의 경우 객체의 내용을 비교한다.

== 연산자는 객체의 참조를 비교한다.

A, B 두 객체의 내용이 같더라도 객체 자체가 서로 다르다면 equals()는 true를 반환하고 == 연산자는 false를 반환하게 된다.

동등성

동등성은 논리적으로 객체의 내용 을 비교하는 개념이다.

앞서 설명한 것 처럼 equals() 메소드를 통해서 동등성을 비교할 수 있다.

public class Apple {

    private final int weight;

    public Apple(int weight) {
        this.weight = weight;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Apple apple = (Apple) o;
        return weight == apple.weight;
    }

    @Override
    public int hashCode() {
        return Objects.hashCode(weight);
    }

    public static void main(String[] args) {
        Apple apple = new Apple(100);
        Apple anotherApple = new Apple(100);

        System.out.println(apple.equals(anotherApple)); // true
    }
}

main 에서 equals 메소드를 통해 apple과 anotherApple을 비교하고자 한다.

equals()메소드를 override해서 무게를 비교했을때, 무게가 같으면 true를 반환하게 했다.

이전포스트에서 언급한대로 equals()를 override 하면서 hashCode() 메소드 또한 override를 했고 main에 있는 출력 메소드에서는 무게가 동일하기 때문에 true를 반환하게 된다.

동일성

동일성은 객체가 메모리 상에서 같은 객체인지 비교하는 개념이다.

== 연산자를 사용하게 되고 두 객체의 참조를 비교하여 두 변수가 동일한 객체를 가리키고 있는지를 확인한다.

public static void main(String[] args) {
    Apple apple1 = new Apple(100);
    Apple apple2 = new Apple(100);
    Apple apple3 = apple1;

    System.out.println(apple1 == apple2); // false
    System.out.println(apple1 == apple3); // true
}

apple1과 apple3는 같은 객체를 바라보고 있고 apple2는 새로 생긴 새로운 객체이므로 다음과 같은 출력의 차이가 존재하게 된다.

재밌는점

재밌게도 equals() 메소드 내부에서도 == 연산자를 사용하게되고 == 연산자는 앞서 설명한대로 동일성을 비교한다.

동등성을 비교하기위해서는 equals와 hashcode를 알맞게 override 하는 과정을 거쳐야하며, 모든 클래스는 Object 클래스를 상속하기 때문에 쉽게 override 할 수 있다.

추가적인 궁금증

String은 객체인데 == 비교로 비교가 가능하다. 왜?

문자열 리터럴은 문자열 상수 pool에 저장된다.

동일한 문자열 리터럴을 참조하면 == 연산자가 true를 반환할 수 있다.

하지만 new 키워드를 사용해서 문자열을 생성하게 되면 새로운 객체가 생성되기 때문에 == 연산자가 false를 반환할 수 있다.

문자열 비교시에는 항상 equals() 메소드를 사용하여 동등성 비교를 하는것을 추천한다.

예시

public class StringComparison {
    public static void main(String[] args) {
        String str1 = "안녕하세요";
        String str2 = "안녕하세요";
        String str3 = new String("안녕하세요");
        
        // 동일성 비교
        System.out.println(str1 == str2); // true
        System.out.println(str1 == str3); // false
        
        // 동등성 비교
        System.out.println(str1.equals(str2)); // true
        System.out.println(str1.equals(str3)); // true
    }
}

// String.class equals 오버라이딩 되어있음.
public boolean equals(Object anObject) {
    if (this == anObject) {
        return true;
    }
    return (anObject instanceof String aString)
            && (!COMPACT_STRINGS || this.coder == aString.coder)
            && StringLatin1.equals(value, aString.value);
}

래퍼 클래스의 비교

int와 integer는 서로 정수를 담는 다는 점은 동일하지만 integer는 wrapper class 이다.

이럴때는 비교를 어떻게 해야하지?

래퍼 클래스도 결국 객체이므로 == 연산자는 참조를 비교해 값을 내놓게 된다.

값 비교를 하기 위해서는 equals() 메소드를 사용해야한다.

but, 자바는 특정 범위의 래퍼 객체를 캐싱하므로 값의 Integer 객체가 같은 참조를 가지게 될 수 있다.

예외가 일어나지 않기 위해서는 일반적으로 equals() 메소드를 통해 비교하는게 좋다.

마치며

자바 같은 객체지향 프로그래밍을 수행하다보면 객체끼리의 비교가 꽤 자주 일어나게 된다. 동등성, 동일성에 대한 개념을 잘 알고 적용하는게 중요한 작업이다.

참고

면접 질문 내용과 답변의 일부는 기술 면접 구독 서비스 - 매일메일 에 있다.
흥미로웠다면 구독해보는 것도 추천한다!

profile
누군가의 롤모델이 될 때까지😇

0개의 댓글