자바에서 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와 ==의 명확한 차이를 이해하고, 실무에서 더 이상 헷갈리지 않기를 바란다.
'웹개발 > Java' 카테고리의 다른 글
| Java Stream API 정렬, 실무에서는 이렇게 씁니다 (Comparable, Comparator 완벽 정리) (1) | 2025.07.20 |
|---|---|
| Java Optional 제대로 쓰고 계신가요? 실무에서 자주 하는 실수와 올바른 사용법 총정리 (2) | 2025.07.20 |
| 자바 static 키워드 제대로 알고 써보자 (사용법, 주의사항 총정리) (4) | 2025.07.09 |
| 『Java 날짜 포맷』 SimpleDateFormat 대신 DateTimeFormatter 써야 하는 이유 (코드 포함) (2) | 2025.07.08 |
| Java에서 List와 Set의 차이 완전 정리 (실무 중심) (0) | 2025.07.08 |