반응형
📌 1️⃣ data.get(i) == x
- 비교하는 것:
두 객체의 메모리 주소 (참조값, 레퍼런스) 를 비교함. - 즉, 두 객체가 "물리적으로 같은 객체인가?" 를 비교함.
예시:
Point2 a = new Point2(1, 2);
Point2 b = new Point2(1, 2);
System.out.println(a == b); // false (주소 다름)
- a와 b는 값이 같아도 서로 다른 객체 → 주소 다름 → == 결과는 false.
📌 2️⃣ data.get(i).equals(x)
- 비교하는 것:
두 객체가 가지고 있는 값의 내용이 같은가? 를 비교함. - 즉, ix, iy가 같은지 비교하도록 Point2 클래스에서 equals()를 오버라이딩 했기 때문에 동작함.
예시:
Point2 a = new Point2(1, 2);
Point2 b = new Point2(1, 2);
System.out.println(a.equals(b)); // true (내용 같음)
- equals() 메소드를 오버라이딩 해두었기 때문에 값이 같으면 true가 나옴.
📌 3️⃣ 결론 비교표
비교의미사용 경우
== | 메모리 주소 비교 (같은 객체인지) | 객체가 완전히 동일한 인스턴스일 때 |
.equals() | 값 비교 (내용이 같은지) | 값이 같으면 동일 취급하고 싶을 때 |
📌 4️⃣ 코드에서
if(data.get(i) == x) // (X) 주소 비교 → 서로 다른 객체이면 false
if(data.get(i).equals(x)) // (O) 값 비교 → 같은 좌표값이면 true
따라서 indexOf()에서는 무조건 equals()를 써야 합니다.
📌 5️⃣ 실제 실행 비교 예시
ObjectStack stack = new ObjectStack(10);
stack.push(new Point2(3, 5));
Point2 search1 = new Point2(3, 5);
System.out.println(stack.indexOf(search1));
- == 사용 시 → 결과: -1 (못 찾음)
- equals() 사용 시 → 결과: 0 (찾음)
👉 이것이 바로 자바에서 equals() 오버라이딩이 매우 중요한 이유입니다.
(이걸 감리에서도 코드 품질 이슈로 굉장히 많이 봅니다)
✅ 1단계: equals()와 hashCode()의 완전 원리
📌 equals()의 본질
- equals()는 **"내용 비교"**를 위해 사용
- 기본적으로 Object 클래스는 이렇게 생김:
public boolean equals(Object obj) {
return (this == obj);
}
👉 즉, 오버라이드하지 않으면 결국 ==와 같음 (참조 비교)
📌 hashCode()의 본질
- hashCode()는 객체를 정수로 변환하는 함수 (int 값 반환)
- 주로 HashMap, HashSet, Hashtable 등에서 검색 성능을 위해 사용
- 기본 구현은 Object 클래스에선 native 방식으로 객체 주소 기반으로 계산됨
📌 반드시 지켜야 할 규칙 (equals & hashCode 계약)
규칙 | 설명 |
1 | equals()가 true이면 반드시 hashCode()도 동일해야 한다 |
2 | hashCode()가 다르다고 해서 equals()가 반드시 false일 필요는 없다 |
👉 핵심: equals() → hashCode() 일관성 유지
📌 예제 (Point2 클래스 개선)
class Point2 {
private int ix;
private int iy;
public Point2(int x, int y) {
ix = x;
iy = y;
}
@Override
public boolean equals(Object obj) {
if (this == obj) return true;
if (obj == null || getClass() != obj.getClass()) return false;
Point2 other = (Point2) obj;
return ix == other.ix && iy == other.iy;
}
@Override
public int hashCode() {
return Objects.hash(ix, iy);
}
}
이렇게 equals와 hashCode를 항상 세트로 오버라이드한다.
✅ 2단계: HashMap, HashSet과의 관계
📌 HashMap은 이렇게 작동함:
1️⃣ 객체 → hashCode() 호출 → 버킷 결정
2️⃣ 버킷 안에서 equals() 호출 → 진짜 같은지 비교
📌 예제
Set<Point2> set = new HashSet<>();
set.add(new Point2(1, 2));
set.add(new Point2(1, 2));
System.out.println(set.size()); // 1
- equals(), hashCode()가 잘 작성되었으면 중복 삽입 안 됨
- 둘 중 하나라도 잘못 작성되면 → 중복 허용됨 → Set 성능 저하 발생
📌 HashMap도 거의 동일
Map<Point2, String> map = new HashMap<>();
map.put(new Point2(1, 2), "A");
map.put(new Point2(1, 2), "B");
System.out.println(map.size()); // 1
System.out.println(map.get(new Point2(1, 2))); // B
✅ 3단계: 자주 묻는 고급 equals 문제
질문 | 핵심 의도 |
equals()와 ==의 차이는? | 값 비교 vs 참조 비교 |
hashCode()를 왜 오버라이드해야 하는가? | HashMap, HashSet에서 동작 보장 |
hashCode()를 안 오버라이드하면? | 중복 삽입, 검색 실패 |
equals()가 true인데 hashCode()가 다르면? | Hash 자료구조 오류 발생 |
hashCode()가 같아도 equals()가 false일 수 있나? | 네 (Hash 충돌 허용) |
✅ 4단계: 핵심 한줄
"자바에서 hash 기반 자료구조를 사용할 때 equals()와 hashCode()는 항상 쌍으로 재정의 되어야 한다."
반응형
'자료구조 알고리즘 자바' 카테고리의 다른 글
스택 Stack 접시 쌓기 LIFO 큐 Queue 줄 서기 FIFO 자바 자료구조 알고리즘 (0) | 2025.06.09 |
---|