본문 바로가기

JAVA

equals()와 hashCode()

equals()와 hashCode()란?

두 메서드는 Object 클래스에 정의되어있다.

따라서 어떤 객체라도 equals()와 hashCode() 메서드를 사용할 수 있다.

어떤 객체가 논리적으로도, 물리적으로도 완전히 동일한지 확인할 때 사용된다.

 

자바에서의 동일성은 equals()의 반환 값이 true이고 hashCode()의 반환값이 같다면, 두 객체는 완전히 동일하다고 판단한다.

하지만, 둘 중 하나라도 다르다면 동일한 객체가 아니므로 정확성을 위해 두 메서드를 함께 오버라이딩(재정의)하는 것이 좋다.

 

equals()

두 객체의 내용이 같은지 확인하는 메서드

 

- 기본 동작

'==' 와 같이 객체의 주소값을 비교하여, 주소값이 같다면 true, 다르다면 false 반환

 

-오버라이드 목적

물리적으로 다른 메모리에 위치하는 객체여도(=주소값이 달라도) 논리적으로 동일함을 구현하기 위해(=내용이 같은지 확인)

 

public class User {
	
    int id;
    String name;
    
    public User(int id, String name) {
    	this.id = id;
        this.name = name;  
    }
    
    public static void main(String[] args) {
    	
        User user1 = new User(1001, "홍길동");
        User user2 = new User(1001, "홍길동");
        // user1과 user2는 내용은 같지만, 주소값이 다른 상태
    	
        // 둘의 주소값이 같니? 
    	System.out.println(user1.equals(user2)); // false 반환
    	
    }
    
}

 

기본적으로 equals()는 객체의 주소값을 비교하는 것이어서 각각 다른 곳을 가리키는 User1과 User2를 다르다고 인식한다.

하지만 주소값이 아닌 순수한 내용(1001, 홍길동)이 같은지 알아보기 위해서는 equals() 메서드를 오버라이딩하는 과정이 필요하다.

 

public class User {
	
    int id;
    String name;
    
    public User(int id, String name) {
    	this.id = id;
        this.name = name;  
    }
    
    @Override
    public boolean equals(Object obj) {
    	
        // 참조변수의 형변환 전에는 반드시 instanceof로 확인해야함
        // 왜? obj는 다 받아주는 애라 어떤 값이 들어올지 모르기 때문에
    	if(!(obj instanceof User)) {
    		return false;
    	}
    	
    	User user = (User)obj; // 형변환
    	return this.id == user.id && this.name.equals(user.name);
    	
    }
    
    public static void main(String[] args) {
    	
    	User user1 = new User(1001, "홍길동");
    	User user2 = new User(1001, "홍길동");
        // user1과 user2는 내용은 같지만, 주소값이 다른 상태
    	
        // 내용 자체를 비교하도록 equals()를 오버라이딩 했으므로
    	System.out.println(user1.equals(user2)); // true
    	
    }
    
}

 

hashCode()

두 객체가 같은 객체인지 확인하는 메서드

 

- 기본 동작

객체의 주소를 int형으로 변환해서 반환. 객체의 해시코드를 반환.

 

- 오버라이드 목적

두 개의 서로 다른 메모리에 위치한 객체가 동일성을 갖기 위해

 

해시코드란, JVM이 인스턴스를 생성할 때 메모리 주소를 변환해서 부여하는 코드이다.

실제 메모리 주소값과는 별개의 값이며 실제 메모리 주소는 System 클래스의 identifyHashCode()로 확인할 수 있다.

 

public class User {
	
    int id;
    String name;
    
    public User(int id, String name) {
    	this.id = id;
        this.name = name;  
    }
    
    @Override
    public boolean equals(Object obj) {
    	
    	if(!(obj instanceof User)) {
    		return false;
    	}
    	
    	User user = (User)obj;
    	return this.id == user.id && this.name.equals(user.name);
    	
    }
    
    public static void main(String[] args) {
    	
        User user1 = new User(1001, "홍길동");
        User user2 = new User(1001, "홍길동");
        // user1과 user2는 내용은 같지만, 주소값이 다른 상태
    	
        // 내용 자체를 비교하도록 equals()를 오버라이딩 했으므로
    	System.out.println(user1.equals(user2)); // true
        
        // 각각 다른 해시코드를 가지고 있는 것을 확인
    	System.out.println(user1.hashCode());	 // 118352462
    	System.out.println(user2.hashCode());	 // 1550089733
    	
    }
    
}

 

서로 다른 메모리를 가리키기 때문에 각자 다른 해시코드를 가지고 있는 것을 확인할 수 있다.

이를 동일하게 구현하기 위해서는 hashCode()를 아래와 같이 오버라이딩해야 한다.

 

import java.util.Objects;

public class User {
	
    int id;
    String name;
    
    public User(int id, String name) {
    	this.id = id;
        this.name = name;  
    }
    
    @Override
    public boolean equals(Object obj) {
    	
    	if(!(obj instanceof User)) {
    		return false;
    	}
    	
    	User user = (User)obj;
    	return this.id == user.id && this.name.equals(user.name);
    	
    }
    
    @Override
    public int hashCode() {
    	return Objects.hash(id, name);
    }
    
    public static void main(String[] args) {
    	
        User user1 = new User(1001, "홍길동");
        User user2 = new User(1001, "홍길동");
        // user1과 user2는 내용은 같지만, 주소값이 다른 상태
    	
        // 내용 자체를 비교하도록 equals()를 오버라이딩 했으므로
    	System.out.println(user1.equals(user2)); // true
    	
    	// hashCode()를 오버라이딩하여 동일성을 갖도록 하였더니 같은 주소값을 가짐
    	System.out.println(user1.hashCode()); // 54182054
    	System.out.println(user2.hashCode()); // 54182054
        
        // 참고로 해시코드는 같지만, 오버라이딩을 해도 절대 바뀌지 않는 값이 있다
        // identityHashCode()은 모든 객체에 대해 항상 다른 해시코드값을 반환할 것을 보장
    	System.out.println(System.identityHashCode(user1)); // 118352462
    	System.out.println(System.identityHashCode(user2)); // 1550089733
    	
    }
    
}

 

결론

equals()의 결과가 true인 두 객체의 해시코드는 반드시 같아야 한다.

따라서, equals()를 오버라이딩하면 hashCode()도 오버라이딩 해주자.

 


출처

atoz-develop.tistory.com/entry/%EC%9E%90%EB%B0%94-Object-%ED%81%B4%EB%9E%98%EC%8A%A4-%EC%A0%95%EB%A6%AC-toString-equals-hashCode-clone

'JAVA' 카테고리의 다른 글

switch문의 제약 조건  (0) 2020.09.29
Properties 클래스  (0) 2020.09.26
Scanner 클래스  (0) 2020.09.15
Java 기초  (0) 2020.09.12
6장  (0) 2020.08.21