Java 使用两个(或更多)对象作为HashMap键

Java 使用两个(或更多)对象作为HashMap键,java,hash,map,Java,Hash,Map,我想在HashMap中存储某些对象。问题是,通常只使用单个对象作为键。(例如,您可以使用字符串。)我要做的是使用多个对象。例如,一个类和一个字符串。有没有一种简单明了的方法来实现这一点?我倾向于使用列表 map.put(Arrays.asList(keyClass, keyString), value) 您可以创建一个holder类,其中包含您想要作为键的类和字符串 public class Key { public MyClass key_class; public Str

我想在HashMap中存储某些对象。问题是,通常只使用单个对象作为键。(例如,您可以使用字符串。)我要做的是使用多个对象。例如,一个类和一个字符串。有没有一种简单明了的方法来实现这一点?

我倾向于使用列表

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

您可以创建一个holder类,其中包含您想要作为键的类和字符串

public class Key {

    public MyClass key_class;
    public String key_string;

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

}

可能不是最好的解决方案,但有一种可能性。

据我所知,最简单的方法是创建一个包装器类并重写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,从而允许对多个键进行哈希和相等检查


此外,为了安全起见,我建议将对象设置为不可变(不可编辑),但这纯粹是首选项。

您的意思是,对象将由两个键设置关键帧,或者更确切地说是由两个东西组成的键

如果你想要第一箱。也就是说,由两个键(比如一个类或一个对象)设置键的对象,需要使用两个映射

Map<Key1, value>

Map<Key2, value>
Map
地图
在第二种情况下,您需要地图地图,因此:

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

您的密钥必须实现hashCode和equals。如果它是一个SortedMap,它还必须实现可比较的接口

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");
公共类MyKey实现了可比较的
{
私有整数i;
私有字符串;
公钥(整数i,字符串s)
{
这个。i=i;
这个.s=s;
}
公共整数getI(){return i;}
公共字符串get(){return s;}
@凌驾
公共int hashcode()
{
返回i.hashcode()+31*s.hashcode();
}
@凌驾
公共布尔等于(对象o)
{
如果(o==this)返回true;
如果(o==null | |!(o instanceof MyKey))返回false;
MyKey cp=MyKey.class.cast(o);
收益率i.equals(cp.i)和s.equals(cp.s);
}
公共整数比较(MyKey cp)
{
如果(cp==this)返回0;
int i=i.compareTo(cp.i);
如果(i!=0)返回i;
返回s.compareTo(cp.s);
}
@凌驾
公共字符串toString()
{
返回“(“+i+”;“+s+”)”;
}
}
publicmap=newhashmap();
map.put(新的MyKey(1,“你好”),“世界”);

Apache Commons Collections有一个多键映射,它可以为您实现以下功能:


看起来它最多可以处理5个“键”。

我完全同意,在一些地方,人们建议创建一个包含其他键的“键”类。我只是想补充一个有用的提示

如果您使用eclipse或netbeans,它们有一个很好的选择——您可以告诉eclipse基于一个或多个成员创建equals和hashcode方法。因此,您只需选择要检索的成员,NB就会创建需要为您编写的大部分代码

当然,当我只想通过一个对象进行检索时,我通常只是将hashcode和equals方法委托给该对象(委托equals可能会有问题,因为这意味着您的一个“keyholder”类将等于它的键所在的对象,但这很容易修复(而且通常不会产生任何影响)

所以在我的脑海里:

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();
    }
}
这就是它的全部内容,如果您要求,eclipse将为您完成最后两项


顺便说一句,我知道我有公共成员,公共最终成员与拥有getter完全一样——这不是一个糟糕的想法。我最近开始在像这样的小型实用程序类上使用这种模式。如果成员不是最终成员,情况会更糟,因为这就像拥有一个setter(这是我最近尽量避免的)。

可以使用apache的commons集合库解决这个问题。 下面是一个简单的例子:

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

否,任何
列表
(或至少任何
抽象列表
,其
数组.asList
为)是由其元素的哈希代码决定的。我只是查找它,因为我有相同的想法。很容易做到,但它的缺点是不记录列表中的内容。是类、字符串还是字符串?还是类名和字符串?是的,但有一些方法可以处理,例如创建一个静态getHashList方法当然,我也会推荐Pierre的Key类用于长寿命映射。另一个问题是,与实现良好的自定义类相比,列表中hashCode和equals的实现成本较高。如何实现成本较高?您应该以任何方式执行相同的操作。有一个额外的对象取消引用,但这不太可能导致缓存丢失。任何用作键的类都需要正确重写equals()和hashCode()。我喜欢这种方法,但添加hashCode和equals方法是用例的强制性要求。我还将使其成为不可变的。请注意,这是重复的,尽管您提供了一个示例。