Skills/Java

Java - equals(), hashcode() 메서드의 사용

aoaa 2022. 10. 1. 22:08

 

 

 Java에서는 두 객체를 비교할 때 사용하는 메서드로 equlas()가 있는데 각 차이점을 알아보겠습니다.

 


1. Object class

 설명에 앞서 Object class에 대해 짚고 넘어가겠습니다.

클래스 선언 시 extends 키워드로 상속하지 않는다면 java.lang.Object 클래스를 상속하게 됩니다. 이는 무엇을 의미하느냐 

Java의 모든 클래스는 Object 클래스의 Super 클래스거나 sub클래스라는 의미입니다. 

 Object 클래스에는 필드가 없고 메서드로만 구성되어 있는데, 이 메서드들이 모든 클래스가 Object를 상속하기 때문에 모든 클래스에서 사용이 가능한 것입니다. 

 Java 공식 문서를 보면 getClass, hashCode, equals, clone, toString .. 등등을 확인해볼 수 있습니다. 

 


2. equals()의 객체비교

 공식 문서를 보면 equlas()의 메서드 패러미터를 보면 Object obj 즉 객체임을 확인할 수 있습니다. Object가 최상위 타입이므로 모든 객체는 Object 타입으로 자동 타입변환 될 수 있음을 의미합니다. 

 여기서 객체를 비교한다는 것은 객체가 저장하고 있는 데이터가 동일함을 의미하는데 예시를 통해 살펴보겠습니다. 

public class Solution {
    public static void main(String[] args) throws IOException {
        System.setIn(new FileInputStream("src/input.txt"));

		String str1 = "Hi";
        String str2 = "Hi";
        String str3 = new String("Hi");

        System.out.println(str1 == str2);
        System.out.println(str1 == str3);

        
    }
}    
 // true
 // false

  코드를 보면 str1,2,3 모두 "Hi"라는 문자열을 가지지만 str3는 new String으로 만든 객체여서 문자열만 같지 서로 다른 객체임을 나타내는 것을 알 수 있습니다. 이는 hashCode에서 설명하겠습니다.


3. hashCode() 객체 해시코드

 위의 코드에서 equals가 false를 반환한 이유는 객체의 메모리 번지를 이용*해시코드를 만들어 return 했기 때문입니다.

한 번 해시코드를 통해 식별해보겠습니다.

(*해시코드 : 객체의 주소값을 변환하여 생성한 객체의 고유 정수값)

public class Solution {
    public static void main(String[] args) throws IOException {
        System.setIn(new FileInputStream("src/input.txt"));

        String str1 = "Hello";
        String str2 = "Hello";
        String str3 = new String("Hello");

        System.out.println("str1 == str2 ? " + (str1 == str2));
        System.out.println("str1 == str3 ? " + (str1 == str3));

        System.out.println("str1 hashCode ? " + System.identityHashCode(str1));
        System.out.println("str2 hashCode ? " + System.identityHashCode(str2));
        System.out.println("str3 hashCode ? " + System.identityHashCode(str3));


    }
}

 indentityHashCode를 통해 String의 해시코드를 확인해봤습니다. 이 해시코드의 값이 다르다면 다른 객체로 판단하고, 같으면 equals() 메서드로 다시 비교하게됩니다. 즉 hashCode()에서 true를 반환한다 해도 equals() return 값이 다르면 다른 객체가 되는 것을 의미합니다. 또하나 예시를 들어보겠습니다.

 

class Human {
	private int age;
	private String name;

	public int getAge() {
		return age;
	}
	public void setAge(int age) {
		this.age = age;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
    
----------------------------------------------------------------------
    public static void main(String[] args){
	Human p1 = new Human();
	p1.setAge(27);
	p1.setName("ROME");

	Human p2 = new Human();
	p2.setAge(27);
	p2.setName("ROME");

	System.out.println(p1.equals(p2)); // false
}

 위의 결과처럼 HashCode를 비교해서 false를 반환하는 것을 볼수가 있는데, 이를 equals()를 오버라이딩하여 값이 동일한지 아닌지 비교할 수있도록 해보겠습니다. 

@Override
public boolean equals(Object obj) {

    if (obj == null) {
        return false;
    }

    if (this.getClass() != obj.getClass()) {
        return false;
    }

    if (this == obj) {
        System.out.println("Object Same");
        return true;
    }

    Human that = (Human) obj;

    if (this.name == null && that.name != null) {
        return false;
    }

    if (this.age == that.age && this.name.equals(that.name)) {
        System.out.println("Object Value Same");
        return true;
    }

    return false;
}

// true

 이처럼 오버라이딩을 통해 재정의하여 해당 인스턴스들이 갖고있는 값들이 같은 경우 같을 때 이를 같은 인스턴스로 봐야하는 경우에 equals를 오버라이딩하여 사용합니다.

 

 결론적으로 객체의 동등한 비교를 위해 equals()뿐 아니라  hashCode()도 재정의하여 논리적 동등 객체일 경우 동일 해시코드가 return 하도록 해야합니다. 

(equals() : 두 객체의 내용이 같은지, hashCode() : 두 객체가 같은 객체인지 확인)

 

 

 

참조

 

'Skills > Java' 카테고리의 다른 글

Java - 정적 팩토리 메서드를 고려하는 상황  (1) 2022.10.08
Java - JDBC  (0) 2022.10.04
Java - 바이트 코드  (0) 2022.09.20
Java - JVM & Garbage Collector  (0) 2022.09.16
Java - static import  (0) 2022.08.29