==
는 동등성을 비교한다. 즉, 객체의 참조값(주소값)이 서로 같은지를 검사한다. 두 객체가 서로 같은 객체인지를 판별하는 것이다.
Java Runtime Data Area 의 Stack 영역에 변수가 저장된다. 해당 변수에 저장된 상수는 Runtime Constant Pool 에 저장되어 있고, Stack 의 변수 선언부는 해당 Runtime Constant Pool 의 주소값을 가지게 되는 것이다.
만약 서로 다른 두 변수가 같은 상수 값을 가진다면 Runtime Constant Pool 에 동일한 주소값을 가지게 되는 것이다. 그렇기 때문에 ==
를 이용한 주소값 비교가 가능한 것이다.
Object 클래스의 equals()
는 두 객체가 서로 동일한지를 검사하기 위해 사용된다.
public boolean equals(Object obj) {
return (this == obj);
}
2개의 서로 같은 문자열을 생성해서 이를 비교한다고 생각해보자. 이 2개의 문자열은 서로 다른 메모리 상에 할당될 것이다. 그런데 equals()
를 사용하면 true를 반환한다. 그 이유는 String.class 가 이 equals()
메소드를 오버라이딩해 논리적으로 동등한지를 비교하기 때문이다.
논리적으로 동등하다는 의미는, 두 객체가 참조값이 다르더라도 내부 value 가 서로 동일하다는 것을 의미한다.
hashCode()
는 객체의 메모리 주소 값을 이용해 해시코드를 만들어 반환한다. 이 해시코드는 객체를 서로 식별하기 위해서 사용된다.
HashSet, HashMap, HashTable은 이 hashCode()
를 이용해서 두 객체가 서로 동등한지를 판단하고 중복된 데이터의 저장을 허용하지 않는다.
만약 두 객체를 equlas()
연산을 통해 비교한다고 가정해보자.
Book book1 = new Book();
Book book2 = new Book();
book1.setId(1);
book2.setId(1);
book1.eqauls(book2); // return false
위 두 객체 book1
,book2
는 서로 같은 id 값을 가지고 있기 때문에 논리적으로 동등한 객체이다.
하지만 두 객체를 equals()
메소드를 통해 비교한다면 false
를 반환한다. 두 객체의 참조 값이 다르기 때문이다. 그렇기 때문에 equlas()
를 오버라이드해서 논리적으로 동등한 객체인지를 판별할 필요가 있다.
위에서 언급했듯 Hash 관련 컬렉션 프레임워크는 hashCode()
를 이용해 해시코드를 가지고 두 객체를 판별한다.
위의 예시를 적용한다면 두 객체 book1
,book2
는 서로 다른 객체이기 때문에 논리적으로 동등하지만 같은 메모리 상에 존재하지 않기 때문에 hashCode()
를 사용하는 컬렉션에 중복된 채로 존재할 것이다.
따라서 아래와 같이 hashCode()
를 재정의할 필요가 있다.
@Override
public int hashCode(){
final int PRIME = 17;
return PRIME + getId();
}
book1
과 book2
는 서로 같은 객체로 판별되어 1개의 데이터만 저장될 것이다.