Использование двух (или более) объектов в качестве ключа HashMap

Я хочу сохранить определенные объекты в HashMap. Проблема в том, что обычно вы используете только один объект в качестве ключа. (Вы можете, например, использовать String.) Что я хочу сделать, чтобы использовать несколько объектов. Например, класс и строка. Есть ли простой и чистый способ реализовать это?

Ответ 1

Ключ должен реализовывать hashCode и равен. Если это 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");

Ответ 2

Я предпочитаю использовать список

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

Ответ 3

Самый простой способ, который я знаю, - сделать класс-оболочку и переопределить 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 и все остальное, но таким образом вы переопределили equals и hashcode, тем самым позволяя проверку хэша и равенства на ваших нескольких ключах.

Кроме того, я бы рекомендовал сделать объекты неизменяемыми (не редактируемыми) для безопасности, но это чисто предпочтение.

Ответ 5

Вы имеете в виду, что на объект будут введены два ключа, или, скорее, ключ, который состоит из двух вещей.

Если вам нужен первый случай. То есть, объектив, на который ссылаются два ключа, скажем, класс или объект, вам нужно использовать две карты.

Map<Key1, value>

Map<Key2, value>

Во втором случае вам понадобится карта карт, поэтому:

Map<Key1, Map<Key2, value>>

Ответ 6

Вы можете создать класс держателя, который содержит класс и строку, которые вы хотите использовать в качестве ключей.

public class Key {

    public MyClass key_class;
    public String key_string;

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

}

Возможно, это не лучшее решение, но возможность.

Ответ 7

Есть несколько мест, где люди предлагают создать класс "Ключ", содержащий других, я полностью согласен. Просто подумал, что добавлю полезный намек.

Если вы используете eclipse или netbeans, у них есть хороший вариант - вы можете сказать Eclipse создать методы equals и hashcode, основанные на одном или нескольких членах. Таким образом, вы просто выбираете члена (или членов), который хотите получить, и NB создает большую часть кода, который вам нужно написать для вас.

конечно, когда я просто хочу получить один объект, я просто просто делегирую хэш-код и методы равным этому объекту (делегирование равных может быть проблематичным, поскольку это означает, что один из ваших классов "Key holder" будет равен объект, который является ключом, но который довольно легко фиксируется (и обычно это ничего не будет влиять)

так от головы:

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();
    }
}

Это все, что нужно, и затмение будет делать последние два для вас, если вы попросите его.

Кстати, я знаю, что у меня есть публичные участники, публичный конечный член - это точно то же самое, что и геттер - не очень страшная идея. В последнее время я использую этот шаблон на небольших урочных классах. Если член не был окончательным, это было бы хуже, потому что это было бы похоже на создание сеттера (что-то я стараюсь избегать в наши дни).

Ответ 8

Можно решить эту проблему, используя apache commons collection 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));