시냅스

Java Equals와 HashCode, == 와 차이 본문

Java, Spring

Java Equals와 HashCode, == 와 차이

ted k 2023. 2. 11. 11:31

Equals 와 == 의 차이

 

Primitive type (원시타입)

  • Call by value
  • 주소로 변수 값을 바로 확인하여 계산하기 때문에 == 비교가 가능

 

Reference type (원시타입 이외 모두)

  • Call by reference
  • 주소값을 참조(포인터) 하여 사용하기 때문에 == 비교를 하게 될 경우 주소값을 비교하게 된다.
  • String을 new (builder, buffer 포함)를 사용하지 않고 리터럴로 생성한 경우
    • String은 string constant pool 이라는 영역에 속한다. (intern)
    • 같은 값에 한해서는 같은 주소값을 같게 된다.
    • 따라서 == 비교가 가능하다.
  • 이때 객체 내부에 Equals()를 override 하여 객체간 값에 대한 비교를 할 수 있다.

 

Equals 와 HashCode

  • Eqauls와 HashCode는 한 셋트다
    • Hash 값을 사용하는 Collection(HashSet, HashMap, HashTable)을 제외하면 사실 Equals만 사용해도 구현은 무관하다
    • 다만, 요구사항이 변한다거나, 협업 환경에서의 통일, 성능 등을 고려하면 같이 구현하는 것이 바람직하다.
  • Equals 는 재정의하여 주소값을 가지는 모든 객체의 값에 관한 비교를 수행할 수 있도록 한다.
  • HashCode 는 Hash 알고리즘에 의해 객체의 주소값을 토대로 일정한 리턴값을 보내주게 된다.
    • 자바 API에서는 다음과 같이 말한다.
    • 어떤 두개 객체에 대하여 equals() 메소드를 사용하여 비교한 결과가 true인 경우, 두 객체의 hashcode() 메소드를 호출하면 동일한 int 값을 리턴해야 한다.
    • 두 객체를 equals() 메소드를 사용하여 비교한 결과 false를 리턴했다고 해서 hashcode() 메소드를 호출한 int 값이 무조건 달라야 할 필요는 없다. 하지만, 이 경우 서로 다른 int 값을 제공하면 hashtable의 성능을 향상시키는 데 도움이 된다.
  • 종합하면, HashCode로 객체에 관한 판별을 하고, Equals로 객체에 관한 값을 비교할 수 있게 한다.

https://www.scaler.com/topics/hashcode-in-java/

 

예시코드

class AClass {
    int a;
    int b;
    Cclass c;

    public AClass(int a, int b) {
        this.a = a;
        this.b = b;
    }

    public AClass(int a, int b, Cclass c) {
        this.a = a;
        this.b = b;
        this.c = c;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (!(o instanceof AClass)) return false;

        AClass aClass = (AClass) o;

        if (a != aClass.a) return false;
        if (b != aClass.b) return false;
        return c != null ? c.equals(aClass.c) : aClass.c == null;
    }

    @Override
    public int hashCode() {
        int result = a;
        result = 31 * result + b;
        result = 31 * result + (c != null ? c.hashCode() : 0);
        return result;
    }
}
  • A클래스는 내부에 값과 객체 C를 가진다.

 

class Cclass {
    private int a;

    public Cclass(int a) {
        this.a = a;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (!(o instanceof Cclass)) return false;

        Cclass cclass = (Cclass) o;

        return a == cclass.a;
    }

    @Override
    public int hashCode() {
        return a;
    }
}
  • C클래스는 값 하나를 가진다.

 

public class Eqauls {
    public static void main(String[] args) {
        AClass aa = new AClass(1, 2, new Cclass(1));
        AClass bb = new AClass(1, 2, new Cclass(1));
        System.out.println(aa.equals(bb)); // true
        System.out.println(aa == bb); // false

        AClass aa1 = new AClass(1, 2);
        AClass bb1 = new AClass(1, 2);
        System.out.println(aa1.equals(bb1)); // true
        System.out.println(aa == bb); // false

        Set<AClass> a1 = new HashSet<>();
        a1.add(aa1);
        a1.add(bb1);
        System.out.println(a1.size()); // 1
    }
}
  • HashSet인 a1은 AClass에서 재정의한 Equals 나 HashCode를 삭제한다면 객체가 같지 않다고 판별한 이유로 사이즈는 2가 나올 것이다.
Comments