본문 바로가기
자료구조 알고리즘 자바

equals()와 ==의 차이는 값 비교 vs 참조 비교

by aiyoon 2025. 6. 9.
반응형

📌 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()는 항상 쌍으로 재정의 되어야 한다."

반응형