2009-07-27 3 views
11

특정 객체를 HashMap에 저장하려고합니다. 문제는 대개 단일 객체를 키로 사용한다는 것입니다. 예를 들어, String을 사용할 수 있습니다. 여러 객체를 사용하려면 어떻게해야합니까? 예를 들어, 클래스와 문자열. 거기에 구현하는 간단하고 깨끗한 방법이 있습니까?두 개 이상의 객체를 HashMap 키로 사용하기

답변

14

당신 키의 해시 코드를 구현하고 동일해야합니다. 그것은 의 SortedMap 경우, 그것은 또한 Comparable 인터페이스를 구현해야한다

public class MyKey implements Comparable<MyKey> 
{ 
private Integer i; 
private String s; 
public MyKey(Integer i,String s) 
{ 
this.i=i; 
this.s=s; 
} 

public Integer getI() { return i;} 
public String getS() { return s;} 

@Override 
public int hashcode() 
{ 
return i.hashcode()+31*s.hashcode(); 
} 

@Override 
public boolean equals(Object o) 
{ 
if(o==this) return true; 
if(o==null || !(o instanceof MyKey)) return false; 
MyKey cp= MyKey.class.cast(o); 
return i.equals(cp.i) && s.equals(cp.s); 
    } 

    public int compareTo(MyKey cp) 
    { 
    if(cp==this) return 0; 
    int i= i.compareTo(cp.i); 
    if(i!=0) return i; 
    return s.compareTo(cp.s); 
    } 


@Override 
    public String toString() 
     { 
     return "("+i+";"+s+")"; 
     } 

    } 

public Map<MyKey,String> map= new HashMap<MyKey,String>(); 
map.put(new MyKey(1,"Hello"),"world"); 
8

나는 당신이 열쇠로 사용할 클래스와 문자열을 포함 홀더 클래스를 만들 수있는 목록을

map.put(Arrays.asList(keyClass, keyString), value) 
+1

해당 목록에 대한 Array.asList의 해시 코드가 아닌가요? –

+1

아니요,'List' (또는 Arrays.asList가있는 적어도 모든 AbstractList)의 해시 코드는 해당 요소의 해시 코드에 의해 결정됩니다. 나는 똑같은 생각을했기 때문에 나는 그것을 보았다. –

+2

쉽게 할 수는 있지만 목록에 속한 것을 문서화하지 않는 단점이 있습니다. 그것이 클래스였습니까? 또는 문자열 먼저? 또는 클래스 이름과 문자열? –

1

를 사용하는 경향이있다.

public class Key { 

    public MyClass key_class; 
    public String key_string; 

    public Key(){ 
     key_class = new MyClass(); 
     key_string = ""; 
    } 

} 

아마도 가장 좋은 해결책은 아니지만 가능성이 있습니다.

+3

키로 사용되는 모든 클래스는 equals() 및 hashCode()를 제대로 재정의해야합니다. – notnoop

+2

나는 접근법을 좋아하지만, 해시 코드와 equals 메소드를 추가하는 것은 유스 케이스의 필수 사항이다. 나는 또한 그것을 불변의 것으로 만들 것이다. –

+0

@msaeed와 @Jens Schauder, 포인터에 감사드립니다. –

4

내가 아는 가장 쉬운 방법은 래퍼 클래스를 만들고 hashmap 및 equals를 재정의하는 것입니다. 예를 들어 : 물론

public class KeyClass { 

    private String element1; 
    private String element2; 

    //boilerplate code here 

    @Override 
    public boolean equals(Object obj) { 
     if (obj instanceof KeyClass) { 
      return element1.equals(((KeyClass)obj).element1) && 
       element2.equals(((KeyClass)obj).element2); 
     } 
     return false; 
    } 

    @Override 
    public int hashCode() { 
     return (element1 + element2).hashcode(); 
    } 
} 

, 나는함으로써 당신의 여러 키에 해시와 평등 검사를 허용하는 StringBuilder에 및 어떤 다른,하지만 당신은 등호 및 해시 코드를 오버라이드 (override) 한이 방법을 사용하는 것이 좋습니다 것입니다.

또한 개체를 안전을 위해 불변 (편집 할 수 없음)로 만들 것을 권장하지만 이는 전적으로 환경 설정입니다.

2

오브젝트가 두 개의 키 또는 두 가지 키로 구성된다는 것을 의미합니까?

첫 번째 경우를 원한다면. 즉, 두 개의 키, 즉 클래스 또는 객체에 의해 키잉 된 객체는 두 개의 맵을 사용해야합니다.

Map<Key1, value> 

Map<Key2, value> 

는 두 번째 경우에는 그렇게,지도의지도가 필요합니다

Map<Key1, Map<Key2, value>> 
0

다른 사람들이 "핵심"수업을 만들 것을 제안하는 곳이 몇 군데 있습니다. 전적으로 동의합니다. 그냥 도움이되는 힌트를 추가한다고 생각했습니다.

eclipse 또는 netbeans를 사용하는 경우 좋은 옵션이 있습니다. Eclipse에 하나 이상의 멤버를 기반으로하는 equals 및 hashcode 메소드를 생성하도록 지정할 수 있습니다. 따라서 검색하려는 멤버 (또는 멤버) 만 선택하면 NB가 작성해야하는 대부분의 코드를 만듭니다.

물론 하나의 객체 만 검색하려는 경우 해시 코드와 equals 메소드를 해당 객체에 위임합니다 (equals 위임은 문제가 될 수 있습니다. 이는 "키 홀더"클래스 중 하나가 객체에이 열쇠입니다, 그러나 그것은 아주 쉽게 고정 (그리고 보통 어쨌든 아무 영향을주지 것입니다) 그래서 내 머리 위로 떨어져

을한다 : 모든 작업이 완료

class KeyHolder { 
    public final String key; 
    public final Object storeMe; 

    public KeyHolder(String key, Object storeMe) { 
     this.key=key; 
     this.storeMe=storeMe; 
    } 

    public equals(Object o) { 
     return (o instanceof KeyHolder && ((KeyHolder)o).key.equals(key)); 
    } 

    public hashcode() { 
     return key.hashCode(); 
    } 
} 

하고, 이클립스가 물어 보면 마지막 두 가지를 할 것입니다.

그건 그렇고, 내가 공공 회원을 가지고 있다는 것을 알고, 공개 최종 회원은 게터를 가지고있는 것과 똑같습니다 - 정말 끔찍한 아이디어는 아닙니다. 최근에 이와 같은 작은 유틸리티 클래스에서이 패턴을 사용하기 시작했습니다. 회원이 결승전이 아니라면 세터 (요즘 피하려고하는 것)와 같을 것이므로 악화 될 것입니다.

0

하나는 아파치의 commons 컬렉션 lib의 MultiKey class을 사용하여이 문제를 해결할 수 있습니다. 다음은 간단한 예입니다.

import org.apache.commons.collections.keyvalue.MultiKey; 

HashMap map = new HashMap(); 
MultiKey multiKey = new MultiKey(key1, key2); 

map.put(multikey,value); 

//to get 
map.get(new MultiKey(key1,key2)); 
+1

예를 들어 설명 했음에도 불구하고 [Clay 's answer] (http://stackoverflow.com/a/1190244/157247)와 중복됩니다. –