2023. 1. 23. 16:30ㆍ기술 창고/Java
equals(), hashcode() 함수들은 모든 자바 객체의 부모 객체인 Object 클래스에 정의되어있다.
따라서, 자바의 모든 객체는 equals() 와 hashcode() 함수를 상속받는다.
equals()
equals() 는 해석한 그대로의 기능을 가지고있다.
2개의 객체가 동일한지 검사하기 위한 메소드이다.
equals() 는 2개의 객체가 참조하는 것이 동일한 데이터인지 동일성을 확인한다.
2개의 객체가 가리키는 주소가 동일한 메모리 주소일 경우에 동일하다고 판단하는 것이다.
// 기본적으로 만들어져있는 equals() 메소드
// 해당 메소드를 오버라이딩하여 구현한다.
public boolean equals(Object obj) {
return (this == obj);
}
동일한 객체가 따로 생성이 된다면 그것은 서로 다른 메모리에서 생성되었기 때문에 동일하지 않다고 볼 수 있다.
하지만 프로그래밍을 진행하다보면 같은 값을 지닌 객체의 경우 같은 객체로 인식되어야할 필요가 있을 수 있다.
이런 동등성을 위해 우리는 값으로 객체를 비교하도록 equals() 메소드를 오버라이드해줄 필요가 있는 것이다.
String s1 = new String("Test");
String s2 = new String("Test");
System.out.println(s1 == s2); // false;
System.out.println(s1.equals(s2)); // true;
// String 클래스에서 equals() 오버라이딩
public boolean equals(Object anObject) {
if (this == anObject) {
return true;
}
if (anObject instanceof String) {
String anotherString = (String)anObject;
int n = value.length;
if (n == anotherString.value.length) {
char v1[] = value;
char v2[] = anotherString.value;
int i = 0;
while (n-- != 0) {
if (v1[i] != v2[i])
return false;
i++;
}
return true;
}
}
return false;
}
위의 예시 코드와 같이 String 타입의 동일한 값을 가지는 변수 2개를 생성하였다.
두 개로 나누어서 따로 생성하였기 때문에 값은 같더라도 다른 메모리애서 생성이 되었기 때문에 동일하다고 볼 수 없을 것이다.
하지만 동일한 값을 지니므로 동등하다고는 볼 수 있을 것이다.
위의 코드를 실행해보면 동일성을 비교하는 equals() 메소드를 호출하면 true가 나온다.
이유는 String 클래스 내에서 equals() 메소드를 오버라이딩하여 객체가 같은 값을 갖는지 동등성을 비교하도록 만들어주었기 때문이다.
hashcode()
hashcode() 메소드는 객체의 유일한 Integer 값을 반환한다.
Object 클래스 내에서는 heap 영역에 저장된 객체의 메모리 주소를 반환한다고 하지만 항상 그렇지는 않다고 한다.
hashcode는 Hash와 연관된 자료구조(HashTable, HashMap 등)를 사용할 때 저장되는 위치를 결정하기 위해 사용된다.
// hashCode() 메소드
// 해당 메소드를 오버라이딩하여 구현한다.
// native 키워드는 native code를 이용해 구현되었음을 의미한다.
// 따라서, 개발자들이 native를 직접적으로 사용할 일은 없을 것이다.
public native int hashCode();
// 오버라이딩하여 구현할 때 native 키워드를 뺀 메소드를 오버라이딩하여 구현한다.
public int hashCode();
equals() 와 hashCode() 연관성
동일한 객체는 동일한 메모리 주소를 갖는다는 것을 뜻하므로 동일한 객체는 동일한 hashcode를 가져야한다.
따라서, equals() 를 오버라이딩하여 구현했으면, hashCode() 메소드 또한 오버라이딩하여 같이 구현해주어야 한다.
equals 와 hashCode 의 연관성을 정의해보자면,
- equals() 에 사용된 정보가 수정되지 않는 한, hashcode는 항상 동일한 값을 가지고 있어야한다.
- 비교하고자 하는 두 객체가 equals()를 통해 동일함이 증명되었다면, hashCode() 또한 동일해야 한다.
- 비교하고자 하는 두 객체가 equals()를 통해 동일함이 증명되지 않았다면, hashCode() 는 동일하지 않아도 된다.
정의한 연관성을 간단하게 표현하자면,
(1) object1.equals(object2) == True -> hashCode(object1) == hashCode(object2) 여야 함.
(2) hashCode(object1) == hashCode(object2) 이지만 반드시 object1.equals(object2) == True 일 필요는 없음
hashCode() 메소드 잘못 오버라이딩 시 발생할 문제점
앞서 hashCode() 메소드는 객체의 유일한 값 혹은 저장된 객체의 메모리 주소를 반환한다고 하였는데, 만약 같은 객체에 같은 데이터를 넣어 두 개 생성한다면, 생성된 메모리 주소도 다를 것이고, 해시값도 서로 다를 것이다.
이에 같은 객체에 같은 데이터를 가지고 있다면 동일한 것으로 판단하게끔 하기 위해 hashCode() 메소드를 오버라이딩하는 것인데, hashCode() 메소드를 잘못 오버라이딩하게 된다면 Hash 와 연관된 자료구조를 사용할 때 저장되는 위치값이 다르게 설정되어 동일하다고 판단하지 않고 두 개로 따로 저장되게 될 것이다.
[참고]
'기술 창고 > Java' 카테고리의 다른 글
[Java] 오버로딩 / 오버라이딩 (0) | 2023.01.31 |
---|---|
[Java] StringBuilder / StringBuffer (0) | 2023.01.23 |
[Java] 객체 / 클래스 / 인스턴스 (0) | 2023.01.12 |
[Java] Stack / Heap (0) | 2023.01.12 |
[Java] 자바 컴파일 과정 (0) | 2023.01.12 |