기록창고

hashCode() override 본문

JAVA

hashCode() override

방금시작한사람 2019. 12. 27. 00:13

Map이나 Set에서 key 값을 저장할 때 해쉬를 해서 저장을 한다.

hash를 하기 위해서, Object class 안에 있는 hashCode() 라는 함수를 사용합니다.

 

public native int hashCode();

 

함수는 이렇게 생겼고 뭔지 모르겠지만, int 값을 반환하는 것을 알 수 있습니다.
그래서 Object 마다 모두 hashCode()를 사용할 수 있고, 실제로 hashCode를 통해 해쉬하는 것을 볼 수 있습니다.

아래 코드는 HashMap에 구현되어있는 코드입니다.

put 을 할때 key를 hash하여 넣는 것을 볼 수 있습니다

public V put(K key, V value) {
    return this.putVal(hash(key), key, value, false, true); 
}

static final int hash(Object key) {
   int h;
   return key == null ? 0 : (h = key.hashCode()) ^ h >>> 16;
}

 

아래 예제는 String 를 Set안에 넣어서 사이즈를 확인하는 코드입니다.
Set은 중복이 안되기 때문에 size가 1로 출력되는 것을 알 수 있습니다

public class Main {
    public static void main(String[] args) {
        Set<String> stringSet = new HashSet<>();
        String a = "hello";
        String b = "hello";
        stringSet.add(a);
        stringSet.add(a);
        System.out.println(stringSet.size()); // 1
        System.out.println(a.hashCode()); //99162322
        System.out.println(b.hashCode()); //99162322 hash가 값이 같아서, 중복되지않고 Set에 추가되지 않았다.
    }
}

 

하지만 String Class 말고 사용자 정의 클래스를 보면 다르다.

class MyClass {
    public String myClassString;
    public MyClass(String myClassString) {
        this.myClassString = myClassString;
    }
}

public class Main {
    public static void main(String[] args) {
        Set<MyClass> set= new HashSet<>();
        MyClass myClass1 = new MyClass("first item");
        MyClass myClass2 = new MyClass("first item");
        set.add(myClass1);
        set.add(myClass2);
        System.out.println(set.size()); // 2
        System.out.println(myClass1.hashCode()); //381259350
        System.out.println(myClass2.hashCode()); //2129789493
    }
}

 

위의 출력에서도 myClass1, 2에서 해쉬한 값이 다르기 때문에 Set 안에 중복되게 들어간 것을 볼 수 있다.
이런 문제를 없애기 위해 hashCode()를 오버라이드해서 다시 정의를 해야한다!

 

String Class는 이미 override를 해주었기 때문에 위와 같은 문제가 발생하지 않았다..

그래서 MyClass를 아래와 같이 다시 작성하면 원하는 방향으로 동작할 거 같다.

class MyClass {
    public String myClassString;
    public MyClass(String myClassString) {
        this.myClassString = myClassString;
    }

    @Override
    public int hashCode() {
        // 지금은 String field 만을 가지고 있기 때문에 String의 hashCode를 사용한다.
        // 실제로 이렇게 구현하면 안된다!
        return this.myClassString.hashCode();
    }
}

 

MyClass에서 hashCode 만 오버라이드해서 위의 코드를 실행시키면 잘 될거 같은데, 안된다...

System.out.println(set.size()); //2
System.out.println(myClass1.hashCode()); // -219298173
System.out.println(myClass2.hashCode()); // -219298173 같은 해쉬값이 출력됬음에도 불구하고 사이즈는 그대로 2이다..

....

 

다음 에 계속

'JAVA' 카테고리의 다른 글

String.equals()  (0) 2020.01.19
Collectors GroupingBy  (0) 2020.01.16
JAVA List for 문으로 remove하기  (0) 2020.01.05
equals() override  (0) 2019.12.28
static 에 관하여  (0) 2019.12.22
Comments