✅ == 연산자
- 비교 대상 → 참조값(주소) 또는 기본 타입 값 자체
- 즉, 두 객체가 같은 메모리 주소를 가리키고 있냐를 비교
String a = new String("hello");
String b = new String("hello");
System.out.println(a == b); // false → 주소가 다름
→ 두 문자열은 내용이 같아도, new 연산자를 쓰면 서로 다른 객체가 된다. 즉 주소가 다르다.
✅ equals() 메서드
- 비교 대상 → 객체의 내용
- 즉, 두 객체가 논리적으로 같은 값/의미를 가지고 있냐를 비교
- String의 equals 메서드는 내용 비교를 수행한다.
String a = new String("hello");
String b = new String("hello");
System.out.println(a.equals(b)); // true → 내용이 같으므로
➡️ String 클래스의 equals() 메서드
public boolean equals(Object anObject) {
if (this == anObject) {
return true;
}
return (anObject instanceof String aString) // anObject이 string인지 검사
&& (!COMPACT_STRINGS || this.coder == aString.coder)
&& StringLatin1.equals(value, aString.value);
// equals: byte 배열끼리 비교하는 내부 유틸 메서드
}
💡 하지만 Object의 equals() 메서드는?
public class Object {
public boolean equals(Object obj) {
return (this == obj);
}
}
- obj와 자신을 비교, 결국 == 와 동일 → 참조 비교
✅ '==' 이 있는데, equals()가 필요한 이유
- 컬렉션에서 동등성 비교할 때 쓰인다. (예: HashSet, HashMap, List의 contains())
- 데이터의 “논리적 동등성”을 비교하고 싶은 경우
- 도메인 객체 비교 (ex. 두 회원이 같은 ID를 가지면 같은 사람으로 취급)
✅ Object를 비교할 때 equals() 재정의 안 한 경우
public class User {
private Long id;
private String name;
public User(Long id, String name) {
this.id = id;
this.name = name;
}
}
public class EqualsExample {
public static void main(String[] args) {
User user1 = new User(1L, "Alice");
User user2 = new User(1L, "Alice");
System.out.println(user1.equals(user2)); // false
}
}
- Object의 기본 equals()는 참조(주소)를 비교한다.
- 그러므로 서로 다른 객체라 생각하여 같은 값이더라도 false가 반환된다.
✅ HashSet 일때의 equals() 메서드는?
import java.util.HashSet;
import java.util.Set;
public class EqualsExample {
public static void main(String[] args) {
User user1 = new User(1L, "Alice");
User user2 = new User(1L, "Alice");
Set<User> users = new HashSet<>();
users.add(user1);
users.add(user2);
System.out.println(users.size()); // 2
}
}
- 둘은 값이 같아 보이는데도 HashSet에서 서로 다른 객체로 취급된다.
- 동일한 값인데 중복으로 들어가서 size가 2가 되는 문제가 발생한다.
이런 이유로 equals()를 값 기준 비교로 재정의해야 한다.
✅ 2. hashCode를 재정의하지 않았을 때 생기는 문제
➡️ 먼저 equals 재정의
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof User)) return false;
User user = (User) o;
return Objects.equals(id, user.id) &&
Objects.equals(name, user.name);
}
이렇게 재정의하면:
User user1 = new User(1L, "Alice");
User user2 = new User(1L, "Alice");
System.out.println(user1.equals(user2)); // true → 내용이 같음
// 재정의 하지 않는다면 ==(주소 비교)를 하므로 false가 출력됨
System.out.println(user1 == user2); // false → 여전히 다른 객체
➡️ HashSet 테스트
import java.util.HashSet;
import java.util.Set;
public class Main {
public static void main(String[] args) {
User user1 = new User(1L, "Alice");
User user2 = new User(1L, "Alice");
Set<User> users = new HashSet<>();
users.add(user1);
System.out.println(user1.equals(user2)); // true
System.out.println(users.contains(user2)); // false
}
}
문제 상황
- user1.equals(user2) == true 라면 user1과 2는 같은 객체라고 인식할 텐데
- HashSet에서는 user2가 이미 들어있다고 인식하지 못한다.
→ contains 결과가 false
이유는 HashSet이 내부적으로 이렇게 동작하기 때문이다:
- hashCode()로 먼저 후보 그룹을 찾는다.
- 후보 안에서 equals()로 최종 비교한다.
equals만 재정의하고 hashCode를 그대로 두면,
- user1, user2의 hashCode가 달라 서로 다른 그룹에 들어간다.
- 결국 HashSet에서는 다른 객체라고 인식한다.
public class Main {
public static void main(String[] args) {
User user1 = new User(1L, "Alice");
User user2 = new User(1L, "Alice");
User user3 = new User(2L, "Bob");
System.out.println("user1.equals(user2): " + user1.equals(user2)); // true
System.out.println("user1.equals(user3): " + user1.equals(user3)); // false
System.out.println("user1.hashCode(): " + user1.hashCode());
System.out.println("user2.hashCode(): " + user2.hashCode());
System.out.println("user3.hashCode(): " + user3.hashCode());
}
}

- hashcode()를 재정의 하지 않으면,
- user1과 user2는 같은 이름을 가지고 있으니 같은 hashcode가 나와야 할 것 같지만 다른 값을 출력하게 된다.
✅ hashCode()를 재정의 한다면?
@Override
public int hashCode() {
return Objects.hash(id, name); // id와 name에 따라 일련의 hash 값 생성
}

- 재정의를 하고 코드를 수행하면 user1과 user2가 같은 값이 나오는 것을 확인할 수 있다.
📚 결론
hashCode()와 equals()의 관계
equals()만 재정의하고 hashCode()를 재정의하지 않으면 두 객체가 논리적으로 같다고 판단되더라도
hashCode()가 다를 수 있다. 이로 인해 HashSet이나 HashMap과 같은 해시 기반 컬렉션에서
문제가 발생할 수 있다. 따라서 equals()와 hashCode()는 일관되게 재정의해야 한다.
참고자료
https://www.baeldung.com/java-hashcode
'JAVA' 카테고리의 다른 글
| [JAVA] 객체 지향 프로그래밍의 정의와 특징 (5) | 2025.08.13 |
|---|---|
| [JAVA] 예외(Exception) 정리 (1) | 2025.06.01 |
| [JAVA] ORM 이란? (0) | 2025.05.31 |
| [JAVA] JDBC 정리 (0) | 2025.05.27 |
| [JAVA] 스레드(Thread) 정리 (0) | 2025.03.01 |