[JAVA] 자바 hashCode()
kindof
·2021. 11. 20. 00:23
1. 자바 hashcode()
자바의 hashcode() 메서드는 Object 클래스의 메서드로써, 모든 클래스는 Object 클래스를 상속하기 때문에 사실 상 모든 객체에서 가지고 있는 메서드라고 볼 수 있습니다.
그리고 이 hashCode() 메서드는 해싱 기법에 사용되는 해시함수(hash function)을 구현한 것인데요. 해시함수는 찾고자 하는 값을 입력하면 그 값이 저장된 위치를 알려주는 해시코드(hash code)를 반환합니다.
2. equals()와 hashCode()
equals() 메서드 역시 Object 클래스가 가진 메서드입니다. equals는 매개변수로 객체의 참조변수를 받아서 비교하고, 그 결과를 boolean 값으로 리턴하는데요. 실제 Object 클래스 안에 equals 메서드는 아래와 같이 정의되어 있습니다.
public boolean equals(Object obj){
return (this == obj);
}
위의 코드에서 알 수 있듯이 equals() 메서드는 두 객체의 같고 다름을 참조변수의 값으로 판단하는데요. 그렇기 때문에 서로 다른 두 객체로 equals 메서드로 비교하면 항상 false를 결과로 얻게 됩니다.
따라서, 두 객체가 같은지를 객체가 가진 필드값으로 판단하기 위해서는 equals() 메서드를 오버라이딩해서 정의해야 합니다.
예를 들어, Student 클래스의 객체가 이름과 학번을 가진다고 했을 때 이름과 학번이 모두 동일하다면 두 객체(학생)은 같은 학생이라고 볼 수 있으며 이를 위해서는 아래와 같이 Student 클래스 안에 equals() 메서드를 오버라이딩 해야하죠.
public class Student{
int id;
String name;
// 생성자
public Student(int id, String name){
this.id = id;
this.name = name;
}
// equlas 메서드 오버라이딩
@Override
public boolean equals(Object obj){
if(obj instanceof Student){
Student other = (Student) obj;
return (this.name.equals(other.name) && this.id == other.id);
}
}
}
한편, 위 코드에서 '이름'을 비교할 때도 equals() 메서드를 사용했는데요. 이는 이름이 String 타입(레퍼런스 타입)으로 정의되어 있기 때문입니다.
위에서 만든 Student 클래스를 가지고 아래와 같이 두 객체가 같은지를 비교해보면 학번과 이름이 모두 같기 때문에 Student a, b는 같은 객체임을 볼 수 있습니다.
그런데, 이 부분에서 문제가 생깁니다. 학생 a, b가 같은 객체라면 a와 b에 대한 hashCode() 메서드도 같은 값을 리턴해야 하는데 hashCode()의 결과값은 각각 다른 값을 갖는다는 것입니다.
즉, equals()로 판별했을 때 두 객체가 같았는데 hashCode()로 판별했을 때 두 객체가 달라진다면 해싱의 의미가 사라져버리는 것이죠.
따라서 equals() 메서드를 오버라이딩할 때는 아래처럼 hashCode() 메서드도 이에 맞게 오버라이딩 해주는 것이 두 객체가 같다는 것을 보장하는 데 논리적인 결함이 없앨 수 있는 방법이 됩니다.
public class Student{
int id;
String name;
// 생성자
public Student(int id, String name){
this.id = id;
this.name = name;
}
// equlas 메서드 오버라이딩
@Override
public boolean equals(Object obj){
if(obj instanceof Student){
Student other = (Student) obj;
return (this.name.equals(other.name) && this.id == other.id);
}
}
// hashCode 메서드 오버라이딩
@Override
public int hashCode(){
return id + name.hashCode();
}
3. String 타입과 hashCode()
String 클래스는 문자열의 내용이 달라도 동일한 hashCode()의 결과로 같은 값이 반환될 수 있는데요.
이는 hashCode()의 리턴 타입이 int이기 때문에 4byte로 표현 가능한 범위에서 결과가 나오지만 우리가 만들 수 있는 String 타입의 문자열은 너무나도 많기에 결국 중복되는 값이 생길 수 있기 때문이죠.
이로부터 알 수 있는 사실은 hashCode()가 같다고 해서 두 객체가 같은 객체임을 보장한다는 것은 아니라는 것입니다. 그래서 이를 면밀히 확인하기 위해서는 equals 메서드를 통해 두 String의 내용이 정확히 일치하는지를 확인해야 하겠습니다.
이렇게 이번 시간에는 자바의 hashCode() 메서드와 equals() 메서드에 대해 정리해보고 고민해보는 시간을 가졌습니다.
위에서 계속 한 이야기들을 요약하면 두 가지로 결론이 나옵니다.
1. equals() 메서드로 같은 객체는 같은 hashCode() 결과가 나와야 한다.
2. hashCode() 메서드로 같은 객체가 항상 equals() 메서드로 같은 객체는 아니다.
감사합니다.
'Java & Kotlin' 카테고리의 다른 글
[Java] LinkedList, ArrayList를 구현하는 방식과 이에 따른 성능 비교해보기 (0) | 2021.12.02 |
---|---|
[Java] 제네릭(Generics)에 대해 생각해보기 (0) | 2021.11.23 |
[Java] 자바 람다식과 함수형 인터페이스(Functional Interface) - (1) (0) | 2021.11.02 |
[자바/JAVA] 생성자(Constructor) (0) | 2021.08.02 |
[자바/Java] 오버로딩(Overloading) (0) | 2021.08.02 |