Java에서 HashMap을 위한 Custom Key 정의하기

Java의 HashMap 자료구조는 고유한 값인 Key와 1:1로 연관되는 값(Value)을 하나의 쌍(Pair)로 하여 여러 개의 쌍을 저장하는 자료구조입니다. 흔히 Key 값으로 문자열이나 정수값을 사용하는 것으로도 충분합니다. 그러나 기능에 따라서 개발자가 특별한 Key에 대한 타입을 정의해야할 필요가 있습니다.

만약 개발자가 Key 타입으로 아래와 같은 클래스를 정의했다고 합시다.

public class Identifier {
    private long A;
    private long B;
    private long C;
	
    public Identifier(long A, long B, long C) {
        this.A = A;
        this.B = B;
        this.C = C;
    }
}

그리고 위의 Identifier 클래스를 Key로 하는 HashMap을 사용하는 코드를 아래와 같이 작성했다고 합시다.

HashMap<Identifier, String> map = new HashMap<Identifier, String>();
		
Identifier id1 = new Identifier(1,2,3);
map.put(id1, "White");
		
Identifier id2 = new Identifier(2,1,3);
map.put(id2, "Yellow");
		
Identifier id3 = new Identifier(2,1,3);
map.put(id3, "Red");
		
System.out.println(map.get(id2));

Key로써의 Identifier 클래스의 동일성을 Identifier가 가지는 3개의 필드인 A, B, C의 동일함으로 정의한다고 할때, 두개의 Identifier 객체 o1, o2가 있다고 한다면 o1과 o2가 같을 조건은 o1.A == o2.A && o1.B == o2.B && o1.C == o2.C라고 할 수 있습니다. 이러한 정의대로라면 위의 코드의 결과는 new Identifier(2,1,3)으로 생성된 객체 중 가장 마지막으로 저장된 “Red” 문자열을 출력해야 하는데, “Yellow”를 출력하게 됩니다. 그렇다면 원하는 결과를 얻기 위해서 무엇을 해야 할까요?

HashMap의 Key 타입으로써 기능을 충족하기 위해서는 Object 클래스의 equals와 hashCode 함수를 재정의해야 합니다. 아래가 Identifier 클래스에 이 2개의 함수를 재정의한 전체 코드입니다.

import java.util.Objects;

public class Identifier {
    private long A;
    private long B;
    private long C;
	
    public Identifier(long A, long B, long C) {
        this.A = A;
        this.B = B;
        this.C = C;
    }
	
    @Override
    public boolean equals(Object o) {
        if(this == o) return true;	
        if(o == null || getClass() != o.getClass()) return false;
		
        Identifier other = (Identifier)o;
		
        return other.A == A && other.B == B && other.C == C;
    }
	
    @Override
    public int hashCode() {
        int result = (int)(A ^ (A >>> 32));
        
        result = 31 * result + (int)(B ^ (B >>> 32));
        result = 31 * result + (int)(C ^ (C >>> 32));
		
        return result;
    }
}

위의 equals 함수는 앞서 설명한 동일성에 대한 정의를 코드로 작성한 것입니다. hashCode 함수는 최대한 중복되지 않고 다양한 값을 반환할 수 있어야 함과 동시에 같은 값이라고 한다면 같은 hashCode 값을 반환해야 합니다. 즉, new Identifier(2,1,3)를 2번 호출하여 2개의 객체를 생성했다면 이 2개의 객체에 대한 hashCode 함수의 반환값은 같아야 합니다. 이러한 조건을 최대한 수용할 수 있도록 작성했다고 작성한게 위의 hashCode 함수의 구현입니다만… 이게 애매한지라 hashCode 함수에 대해서만큼은 아래의 코드로 대체할 수 있습니다.

@Override
public int hashCode() {
    return Objects.hash(A, B, C); // import java.util.Objects; 가 필요함
}

이제 실행해 보면, 우리가 원하는 결과를 얻을 수 있습니다. 이상으로 HashMap에 대한 Custom Key 타입을 정의하는 방식에 대한 정리였습니다.

답글 남기기

이메일 주소는 공개되지 않습니다. 필수 필드는 *로 표시됩니다