Java에서 데이터를 비교할 때 == 연산자와 equals() 메서드를 유의해서 사용해야 하는 이유는 Primitive Type과 Reference Type의 동작 방식이 다르기 때문이다.
1️⃣ == 연산자와 equals()의 차이
비교 방법 | 비교 대상 | 비교 내용 | 예제 |
== | Primitive Type | 값을 직접 비교 | int a = 10; int b = 10; a == b → ✅ true |
== | Reference Type | 객체의 주소(참조값)를 비교 | String s1 = "hello"; String s2 = new String("hello"); s1 == s2 → ❌ false |
equals() | 기본적으로 Reference Type | 객체가 의미적으로 같은지를 비교 (Override 가능) | String s1 = "hello"; String s2 = new String("hello"); s1.equals(s2) → ✅ true |
2️⃣ Primitive Type 비교 (== 사용)
Primitive Type(int, double, boolean 등)은 값 자체를 저장하므로, == 연산자로 비교하면 정확하다.
📌 예제 - Primitive Type 비교 (== 사용)
int a = 10;
int b = 10;
System.out.println(a == b); // ✅ true (값 자체 비교)
double x = 3.14;
double y = 3.14;
System.out.println(x == y); // ✅ true (값 자체 비교)
- Primitive Type은 == 연산자로 비교하는 것이 올바른 방법이다.
3️⃣ Reference Type 비교 (== vs equals())
Reference Type(String, Integer, List 등)은 객체의 메모리 주소를 저장한다.
따라서 == 를 사용하면 객체가 같은 주소를 참조하는지를 비교하고, equals()는 객체가 논리적으로 같은지를 비교한다.
String 비교
Java에서 String은 문자열 리터럴 풀(String Pool)을 사용하기 때문에 == 비교 시 주의해야 한다.
📌 예제 - String 비교 (== vs equals() 비교)
String s1 = "hello"; // 문자열 리터럴 (String Pool)
String s2 = "hello"; // 동일한 String Pool 객체 참조
String s3 = new String("hello"); // new 연산자로 새로운 객체 생성
System.out.println(s1 == s2); // ✅ true (같은 String Pool 객체)
System.out.println(s1 == s3); // ❌ false (다른 객체)
System.out.println(s1.equals(s3)); // ✅ true (문자열 값 비교)
- 문자열 비교 시 equals()를 사용해야 한다. (== 는 예상치 못한 결과 발생 가능)
Wrapper Class 비교 (Integer, Double 등)
Integer, Double 같은 Wrapper Class는 값을 비교할 때 equals()를 사용해야 한다.
📌 Wrapper Class(Integer)끼리 비교
Integer는 객체이므로, == 를 사용하면 메모리 주소(참조)를 비교하고, equals()를 사용하면 값을 비교한다.
Integer x = new Integer(100);
Integer y = new Integer(100);
System.out.println(x == y); // false (다른 객체)
System.out.println(x.equals(y)); // true (값이 같음)
- x와 y는 new Integer()로 생성된 별개의 객체이므로 ==는 false지만, equals()는 내부 값이 같아서 true.
📌 Primitive Type(int)와 Wrapper Class(Integer) 비교
1. int와 Integer를 == 로 비교하면, Integer가 자동으로 int로 변환(unboxing)되어 값을 비교한다.
int a = 100;
Integer b = new Integer(100);
System.out.println(a == b); // true (b가 언박싱되어 값 비교)
- b가 int로 변환되면서 100 == 100이 되어 true.
2. 하지만 equals()를 사용할 경우, Integer가 unboxing되지 않으므로 비교 불가능한 상황이 발생할 수 있다.
Integer c = 100;
System.out.println(c.equals(100)); // true (값 비교)
Integer d = null;
System.out.println(d.equals(100)); // NullPointerException 발생! ❌
- d가 null이면 equals() 호출 자체가 불가능하므로 NullPointerException이 발생.
- 따라서, Integer의 equals()를 사용할 때는 null 체크를 먼저 해야 함.
📌 Integer의 캐싱(Caching) 동작 주의사항
Java는 Integer의 값이 -128 ~ 127 범위일 때 캐싱하여 같은 객체를 참조한다.
Integer a = 100; // 오토박싱 (캐싱)
Integer b = 100; // 같은 객체 참조
System.out.println(a == b); // true (같은 객체)
System.out.println(a.equals(b)); // true (값 비교)
Integer c = 200;
Integer d = 200;
System.out.println(c == d); // false (다른 객체)
System.out.println(c.equals(d)); // true (값 비교)
- -128 ~ 127 범위의 값은 캐싱되므로 == 비교 시 true, 하지만 범위를 벗어나면 new Integer()를 호출한 것처럼 다른 객체가 생성되므로 == 비교는 false
List, Set, Map 등 Collection 비교
컬렉션(List, Set, Map 등)은 객체 참조를 비교하면 안 되고, equals()를 사용해야 한다.
📌 예제 - List 비교 (== vs equals())
import java.util.ArrayList;
import java.util.List;
public class Main {
public static void main(String[] args) {
List<String> list1 = new ArrayList<>();
list1.add("A");
list1.add("B");
List<String> list2 = new ArrayList<>();
list2.add("A");
list2.add("B");
System.out.println(list1 == list2); // ❌ false (다른 객체)
System.out.println(list1.equals(list2)); // ✅ true (리스트 내용 비교)
}
}
- 컬렉션 비교 시 equals()를 사용해야 한다. (==는 객체의 참조값을 비교하므로 항상 false가 나올 가능성이 높음)
equals()를 오버라이드해서 비교 방식 변경
Java의 equals()는 기본적으로 객체의 참조값(메모리 주소)을 비교하지만, equals()를 오버라이드하면 객체의 논리적 동등성을 비교할 수 있다.
📌 예제 - Person 클래스에서 equals() 오버라이드
class Person {
String name;
int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public boolean equals(Object obj) {
if (this == obj) return true;
if (obj == null || getClass() != obj.getClass()) return false;
Person person = (Person) obj;
return age == person.age && name.equals(person.name);
}
}
public class Main {
public static void main(String[] args) {
Person p1 = new Person("Alice", 25);
Person p2 = new Person("Alice", 25);
Person p3 = new Person("Bob", 30);
System.out.println(p1 == p2); // ❌ false (서로 다른 객체)
System.out.println(p1.equals(p2)); // ✅ true (값이 동일)
System.out.println(p1.equals(p3)); // ❌ false (값이 다름)
}
}
- 객체 비교 시 equals()를 오버라이드해서 논리적 비교를 수행하도록 구현하는 것이 중요하다.