[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.24OS가 Window 인 경우에는 String hostAddr = java.net.InetAddress.getLocalHost().getHostAddress(); 를 하면 IP를 알 수 있다. 하지만 UNIX나 LINUX에서 사용하게 되면 127.0.0.1 이거나 java.net.UnknownHostException 등의 에러가 나면서 제대로 IP를 조회할 수 없다. OS나 장치에 상관없이 고정 IP를 가져오기 위해선 String hostAddr = ""; try { Enumeration nienum = NetworkInterface.getNetworkInterfaces(); while (nienum.hasMoreElements()) { NetworkInterface ni = nienum.nextEleme… -
[Java] JSTL 로 replace 사용하여 문자열 치환하기
[Java] JSTL 로 replace 사용하여 문자열 치환하기
2021.08.30
댓글을 사용할 수 없습니다.