[Java] Object 클래스_hashCode() 메소드

Devlog·2024년 3월 27일

Java

목록 보기
26/41

✔️ 객체 해시코드(hashCode())

: 객체를 식별하는 하나의 정수값
: Object 클래스의 hashCode() 메소드는
객체의 메모리 번지를 이용해서 해시코드를 만들어
리턴하기 때문에 객체마다 다른 값을 가지고 있음

: 논리적 동등 비교 시 hashCoe()를 오버라이딩할 필요가 있음
컬렉션 프레임워크에서 HastSet, HashMap, Hashtable은
다음과 같은 방법으로 두 객체가 동등한지 비교함

1) hashCode() 메소드를 실행해서 리턴된 해시코드 값이 같은지 확인
2) 해시코드 값이 다르면 다른 객체로 판단하고,
해시코드 값이 같으면 equals() 메소드로 다시 비교함

그렇기 때문에 hashCode() 메소드가 true가 나와도
equals()의 리턴값이 다르면 다른 객체가 됨

ex)
Key 클래스는 equals() 메소드를 재정의해서
number 필드값이 같으면 true를 리턴

그러나 hashCode() 메소드는 재정의하지 않았기 때문에
Object의 hashCode() 메소드가 사용됨
import java.util.HashMap;


class Key{
	public int number;
	
	public Key(int number) {
		this.number = number;
	}
	
	@Override
	public boolean equals(Object obj) {
		if(obj instanceof Key) {
			Key compareKey = (Key) obj;
			if(this.number == compareKey.number) {
				return true;
			}
		}
		
		return false;
	}
	
}

public class KeyExample {
	public static void main(String[] args) {
		//Key 객체를 식별키로 사용해서 String 값을 저장하는 HashMap 객체 생성
		HashMap<Key, String> hashMap = new HashMap<Key,String>();
		
		//식별키 new Key(1)로 "홍길동"을 저장함
		hashMap.put(new Key(1), "홍길동");
		
		//식별키 new Key(1)로 "홍길동"을 읽어옴
		String value = hashMap.get(new Key(1));
		System.out.println(value);
	}
}

💻 결과
null

/*
 * 이런 경우 HashMap의 식별키로 Key 객체를 사용하면
 * 저장된 값을 찾아오지 못함
 * 
 * 왜냐하면 number 필드값이 같더라도 hashCode() 메소드에서
 * 리턴하는 해시코드가 다르므로 다른 식별키로 인식하기 때문
 * 
 * new Key(1) 객체로 "홍길동"을 저장하고,
 * 다시 new Key(1) 객체로 저장된 "홍길동"을 읽으려고 했지만
 * 결과는 null 나옴
 */

→ 의도한 대로 "홍길동"을 읽으려면
다음과 같이 재정의한 hashCode()의
리턴값을 number 필드값으로 했기 때문에
저장할 때의 new Key(1)과
읽을 때의 new Key(1)로 같은 해시코드가 리턴됨

class Key{
	public int number;
	
	public Key(int number) {
		this.number = number;
	}

    @Override
	public boolean equals(Object obj) {
		if(obj instanceof Key) {
			Key compareKey = (Key) obj;
			if(this.number == compareKey.number) {
				return true;
			}
		}
		
		return false;
	}
	
    @Override
	public int hashCode() {
		return number;
	}
	
}

public class KeyExample {
	public static void main(String[] args) {
		//Key 객체를 식별키로 사용해서 String 값을 저장하는 HashMap 객체 생성
		HashMap<Key, String> hashMap = new HashMap<Key,String>();
		
		//식별키 new Key(1)로 "홍길동"을 저장함
		hashMap.put(new Key(1), "홍길동");
		
		//식별키 new Key(1)로 "홍길동"을 읽어옴
		String value = hashMap.get(new Key(1));
		System.out.println(value);
	}
}

💻 결과
홍길동

→ 저장할 떄의 new Key(1)과
읽을 때의 new Key(1)은 사실 서로 다른 객체이지만
HashMap은 hashCode()의 리턴값이 같고,
equals()의 리턴값이 true가 되기 때문에
동등한 객체로 평가함

즉, 같은 식별키로 인식한다는 뜻

결론적으로 말해서 객체의 동등 비교를 위해서는
Object의 equals() 메소드만 재정의하지 말고
hashCode() 메소드도 재정의해서
논리적으로 동등한 객체일 경우
동일한 해시코드가 리턴되도록 해야함

ex) id 필드값이 같을 경우
같은 해시코드를 리턴하도록 하기 위해
String의 hashCode() 메소드를 리턴값을 활용함

String의 hashCode()는 같은 문자열일 경우
동일한 해시코드를 리턴함
class Member {
	public String id;
	
	public Member(String id) {
		this.id = id;
	}
	
	@Override
	public boolean equals(Object obj) {
		// 매개값이 Member 타입인지 확인
		if(obj instanceof Member) {
			//Memeber 타입으로 강제 타입 변환하고
			//id필드값이 동일하니 검사한 후,
			//동일하다면 true를 리턴
			Member member = (Member) obj;
			if(id.equals(member.id)) {
				return true;
			}
		}
		//매개값이 Member 타입이 아니거나
		//id필드값이 다른 경우 false를 리턴
		return false;
	}
	
	//id가 동일한 문자열인 경우
	//같은 해시 코드를 리턴
	@Override
	public int hashCode() {
		return id.hashCode();
	}
}


public class MemberExample {
	public static void main(String[] args) {
		Member obj1 = new Member("blue");
		Member obj2 = new Member("blue");
		Member obj3 = new Member("red");
		
		//매개값이 Member타입이고
		//id필드값도 동일하므로 true
		if(obj1.equals(obj2)) {
			System.out.println("obj1과 obj2는 동등합니다.");
		} else {
			System.out.println("obj1과 obj2는 동등하지 않습니다.");
		}
		
		//매개값이 Member타입이지만
		//id필드값이 다르므로 false
		if(obj1.equals(obj3)) {
			System.out.println("obj1과 obj3은 동등합니다.");
		} else {
			System.out.println("obj1과 obj3은 동등하지 않습니다.");
		}
	}
}

0개의 댓글