[Java] Java equals(), hashCode() 사용 그리고 재정의
Object Class equals(), hashCode()
Object Class 의 equals() 와 hashCode()를 확인하기 위해 name 필드를 가지는 Car 클래스를 만들었다.
빌드 패턴을 이용한 생성자만 존재하며 equals()는 재정의 되지 않은 상태이다.
public class Car {
private final String name;
public static class Builder {
private final String name;
public Builder(String name) {
this.name = name;
}
public Car build() {
return new Car(this);
}
}
private Car(Builder builder) {
name = builder.name;
}
}
Car k3 = new Car.Builder("k3").build(); // k3: Car@6996db8
Car k3_2 = new Car.Builder("k3").build(); // k3_2: Car@1963006a
System.out.println("k3: " + k3); // k3: Car@6996db8
System.out.println("k3_2: " + k3_2); // k3_2: Car@1963006a
Set<Car> set = new HashSet<>(Arrays.asList(k3, k3_2)); // set size : 2
System.out.println("set size : " + set.size()); // set size : 2
System.out.println("k3 eq k3_2 : " + k3.equals(k3_2)); // ke eq k3_2 : false
System.out.println("k3 hashcode : " + k3.hashCode()); // 110718392
System.out.println("k3_2 hashcode : " + k3_2.hashCode()); // 425918570
k3 라는 name을 가지는 인스턴스 객체를 2개 생성했으며, equals() 와 hashCode()를 확인해봤다.
Car 클래스 내에서 재정의 하지 않았기 때문에 Object 의 equals와 hashCode를 사용하게 된다.
public class Object {
public boolean equals(Object obj) {
return (this == obj);
}
}
equals 에서는 객체의 주소를 비교하게 된다. k3라는 생성된 객체들은 힙메모리내에서 다른 주소값을 가지고 있기때문에, equals 에서 false를 반환하게 되는 것이다.
public class Object {
public native int hashCode();
}
hashCode가 다른 이유도 Object 클래스의 hashCode()는 주소값을 변환하여 int 타입으로 반환하기 때문에 주소가 다른 객체이므로 hashCode가 다르다.
override equals()
이제 직접 Car 클래스에서 equals() 메서드를 재정의 하겠습니다.
@Override
public boolean equals(Object obj) {
if (this == obj) return true;
if (obj == null || getClass() != obj.getClass()) return false;
return name.equals(((Car)obj).name);
}
Car 클래스의 equals 메서드는 String 타입의 equals 를 사용하도록 재정의하였다. String 클래스의 equals 메서드는 주소값을 비교하지 않고, 문자열을 비교하기 때문에 같은 name으로 생성된 두 객체는 서로 다른 힙메모리에서 다른 주소값을 갖지만 위와 같은 이유로 true를 반환한다.
Car k3 = new Car.Builder("k3").build(); // Car@15db9742
Car k3_2 = new Car.Builder("k3").build(); // Car@6d06d69c
Set<Car> set = new HashSet<>(Arrays.asList(k3, k3_2));
System.out.println("set size : " + set.size()); // size : 2
System.out.println("k3 eq k3_2 :" + k3.equals(k3_2)); // true
System.out.println("k3 hashcode :" + k3.hashCode()); // 366712642
System.out.println("k3_2 hashcode :" + k3_2.hashCode()); // 1829164700
재정의 하고 코드를 진행하면 equals 메서드에서 true를 반환한다. 하지만 Set 자료구조의 사이즈에서는 여전히 2를 반환한다. Set 자료구조는 값이 중복될 수 없다.
euuals 메서드를 재정의해서 name 필드가 같으면 같은 객체라고 정의하였기 때문에, 1개의 객체가 저장되는 것으로 생각했다, 하지만 HashSet 자료구조에서는 2개의 객체가 저장이 되었다.
Hash 를 사용하는 자바 자료구조는 (HashMap, HashSet, HashTable 등) 객체가 논리적으로 같은지 비교할 때 아래와 같다.
Car 클래스는 equals 메서드만 재정의하였고, hashCode() 메서드는 재정의하지 않았기 때문에, Object 클래스의 hashCode() 메서드를 사용하게 된다. 주소값을 반환하기 때문에 같은 name 이여도 객체의 주소가 다르기 때문에 hashCode 값 역시 서로 다르다.
@Override
public int hashCode() {
return name != null ? name.hashCode() : 0;
}
이제 name 필드의 값이 같으면 hashCode도 모두 동일하다.
Car k3 = new Car.Builder("k3").build(); //Car@d28
Car k3_2 = new Car.Builder("k3").build(); //Car@d28
Set<Car> set = new HashSet<>(Arrays.asList(k3, k3_2));
System.out.println("set size : " + set.size()); // set size : 1
System.out.println("k3 eq k3_2 :" + k3.equals(k3_2)); // true
System.out.println("k3 hashcode :" + k3.hashCode()); // 3368
System.out.println("k3_2 hashcode :" + k3_2.hashCode()); // 3368
재정의 하고 진행하면 Set size 가 1인걸 확인할 수 있다.
위와 같은 내용 떄문에 equals를 재정의하려거든 hashCode도 재정의 하라는(아이템 11) 이펙티브 자바에서도 명시하고 있다.
'Backend > Java' 카테고리의 다른 글
[Java] 매개변수 ... / 점점점 / 자료형 점점점 / 자료형 ... / varargs / 가변인자 (0) | 2021.12.21 |
---|---|
[Java] 빌더패턴(Builder Pattern) 사용하기 (0) | 2021.10.06 |
[Java] 모든 OS에서 서버 고정IP 조회하기 (0) | 2021.09.24 |
[Java] JSTL 로 replace 사용하여 문자열 치환하기 (0) | 2021.08.30 |
[Java]JSP에서 Include 사용방법 (0) | 2021.01.19 |
댓글
이 글 공유하기
다른 글
-
[Java] 매개변수 ... / 점점점 / 자료형 점점점 / 자료형 ... / varargs / 가변인자
[Java] 매개변수 ... / 점점점 / 자료형 점점점 / 자료형 ... / varargs / 가변인자
2021.12.21 -
[Java] 빌더패턴(Builder Pattern) 사용하기
[Java] 빌더패턴(Builder Pattern) 사용하기
2021.10.06 -
[Java] 모든 OS에서 서버 고정IP 조회하기
[Java] 모든 OS에서 서버 고정IP 조회하기
2021.09.24 -
[Java] JSTL 로 replace 사용하여 문자열 치환하기
[Java] JSTL 로 replace 사용하여 문자열 치환하기
2021.08.30