"오늘의 문제를, 내일의 기록으로 남깁니다."

막연한 이론보다, 구체적인 코드가 필요할 때. 직접 겪고 해결한 문제들을 기록합니다. 실무에서 부딪히는 진짜 이슈와, 내가 이해한 방식 그대로 정리한 가이드입니다.

웹개발/Java

자바 equals와 ==의 차이 정확히 알고 계신가요? (실무에서 자주 하는 실수 예시 포함)

자바를잡아 2025. 7. 9. 22:00
반응형

자바에서 equals와 ==를 잘못 써서 난감했던 경험

얼마 전 사내에서 사용 중인 회원 관리 시스템을 점검하는 중이었는데, 갑자기 한 유저가 로그인하지 못하는 황당한 문제가 발생했다. 아이디가 맞는데도 자꾸 로그인 실패 메시지가 떴던 것이다. 원인을 추적하다보니 역시나 자바에서 흔히 하는 실수, equals와 ==의 혼동 때문이었다. 이번 포스팅에서는 equals와 ==의 차이를 명확히 정리하고, 실무에서 자주 하는 실수와 정확한 해결법을 단계별로 소개하겠다.

equals와 ==, 개념부터 확실히 잡자

자바에서 equals와 ==는 비슷한 듯 전혀 다른 연산자이다. 차이점은 아래와 같다.

  • == 연산자: 두 객체가 메모리에서 동일한 위치를 참조하는지 비교 (레퍼런스 비교)
  • equals 메서드: 두 객체의 값(내용)이 같은지 비교 (값 비교)

단순히 숫자나 문자처럼 기본형 데이터를 비교할 땐 큰 문제 없지만, 객체를 비교할 때는 반드시 두 연산자의 차이를 기억해야 한다.

실무에서 자주 발생하는 실수 사례

1. String 비교 시 흔히 하는 실수

가장 흔히 실수하는 케이스가 바로 문자열(String)을 비교할 때다. 자바를 처음 접한 개발자들이 자주 하는 실수가 바로 이것이다.

// 실수 사례
String name1 = "user";
String name2 = new String("user");

if (name1 == name2) {
    System.out.println("이름이 같습니다.");
} else {
    System.out.println("이름이 다릅니다."); // 출력: 이름이 다릅니다.
}

분명 같은 "user"인데 출력은 다르다고 나온다. 이 이유는 name1과 name2가 같은 문자열을 가지고 있지만 서로 다른 메모리 주소를 참조하기 때문이다.

해결 방법: String 비교는 equals로!

정확한 비교를 위해서는 equals를 반드시 써야 한다.

// 올바른 사례
String name1 = "user";
String name2 = new String("user");

if (name1.equals(name2)) {
    System.out.println("이름이 같습니다."); // 출력: 이름이 같습니다.
} else {
    System.out.println("이름이 다릅니다.");
}

2. Integer 객체 비교 시 자주 놓치는 부분

Integer 객체를 비교할 때도 비슷한 문제가 발생한다. 특히 Integer 캐싱 범위(-128 ~ 127) 밖에서는 == 비교가 제대로 동작하지 않는다.

// 실수 사례
Integer a = 200;
Integer b = 200;

if (a == b) {
    System.out.println("같음");
} else {
    System.out.println("다름"); // 출력: 다름
}

여기서 왜 "다름"이 나오는지 의아해할 수 있는데, 자바가 Integer 값을 캐싱하는 범위를 벗어났기 때문이다.

해결 방법: 역시 equals로 비교하자

Integer 비교는 반드시 equals를 사용해야 한다.

// 올바른 사례
Integer a = 200;
Integer b = 200;

if (a.equals(b)) {
    System.out.println("같음"); // 출력: 같음
} else {
    System.out.println("다름");
}

3. 커스텀 객체 비교 시 equals 미정의로 인한 문제

개발자가 직접 만든 클래스의 객체를 equals로 비교할 때 equals를 오버라이드 하지 않은 경우, 의도한 대로 값이 비교되지 않는다.

// 실수 사례
class User {
    String name;

    User(String name) {
        this.name = name;
    }
}

User user1 = new User("홍길동");
User user2 = new User("홍길동");

if (user1.equals(user2)) {
    System.out.println("같음");
} else {
    System.out.println("다름"); // 출력: 다름
}

객체 내용은 같지만 equals가 오버라이딩되지 않았기 때문에 결과는 "다름"이 나온다.

해결 방법: equals 메서드 오버라이딩 필수!

// 올바른 사례
class User {
    String name;

    User(String name) {
        this.name = name;
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj) return true;
        if (obj == null || getClass() != obj.getClass()) return false;
        User user = (User) obj;
        return name.equals(user.name);
    }

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

User user1 = new User("홍길동");
User user2 = new User("홍길동");

if (user1.equals(user2)) {
    System.out.println("같음"); // 출력: 같음
} else {
    System.out.println("다름");
}

equals와 == 제대로 쓰는 간단한 팁 정리

  • 기본형 타입 비교: 반드시 == 사용 (int, char, boolean 등)
  • 객체의 값 비교: 반드시 equals 사용 (String, Integer, 커스텀 객체)
  • 객체 참조 주소 비교: 객체가 동일한 인스턴스인지 확인하고 싶을 때만 == 사용

마무리: equals와 == 혼동하지 말자

자바의 equals와 ==는 겉보기에는 매우 유사하지만 그 목적과 동작 원리는 분명히 다르다. 특히 문자열과 객체 비교 시 equals 메서드를 정확히 사용해야 실수를 줄일 수 있다. 이번 포스팅으로 equals와 ==의 명확한 차이를 이해하고, 실무에서 더 이상 헷갈리지 않기를 바란다.

반응형