自定义泛型类作为哈希映射问题的关键

时间:2011-02-20 14:10:51

标签: java generics set hashmap

我有以下测试代码:

public static final String[] list = {
    "apple","ball","cat","dog","egg","fan","girl","hat","igloo","jerk"  
};

...

HashMap<DoubleKey<Integer, Integer>, String> hm = new HashMap<DoubleKey<Integer, Integer>, String>();
Set<DoubleKey<Integer, Integer>> s = new TreeSet<DoubleKey<Integer, Integer>>();
Random g = new Random();
for(int i=0; i<10; i++){
    int first = g.nextInt(9999) + 1000; 
    int second = g.nextInt(9999) + 1000; 
    DoubleKey<Integer, Integer> k1 = new DoubleKey<Integer, Integer>(first, second);
    DoubleKey<Integer, Integer> k2 = new DoubleKey<Integer, Integer>(first, second);
    s.add(k1);
    hm.put(k2, list[i]);
}

Set<DoubleKey<Integer, Integer>> ts = hm.keySet();
Iterator<DoubleKey<Integer, Integer>> itr = ts.iterator();
while(itr.hasNext()){
    DoubleKey<Integer, Integer> k = itr.next(); 
    System.out.println(k.getFirstKey().toString() + " + " + k.getSecondKey().toString() + " -> " + hm.get(k).toString());
}

System.out.println("----");
Iterator<DoubleKey<Integer, Integer>> sItr = s.iterator();
while(sItr.hasNext()){
    DoubleKey<Integer, Integer> k = sItr.next();
    String currStr = hm.get(k);
    System.out.println(k.getFirstKey().toString() + " + " + k.getSecondKey().toString() + " -> " + currStr);
}

我所做的是创建一个Custom Generic Class DoubleKey&lt; K,J&gt;包含具有两个部分的键。如您所见,Set s 和HashMap hm 的键具有相同的组件,但实例化方式不同( k1 = k2 ) 。当我尝试使用 s 上的键获取 hm 时,它会返回 null ,但是首先打印它显示正确的映射。

Sample Output:

3922 + 2544 -> girl
9267 + 3750 -> hat
3107 + 10929 -> apple
5162 + 8834 -> fan
8786 + 1125 -> cat
10650 + 4078 -> egg
3808 + 7363 -> jerk
1364 + 7657 -> dog
1364 + 4412 -> ball
1583 + 1460 -> igloo
----
10650 + 4078 -> null
1364 + 4412 -> null
1364 + 7657 -> null
1583 + 1460 -> null
3107 + 10929 -> null
3808 + 7363 -> null
3922 + 2544 -> null
5162 + 8834 -> null
8786 + 1125 -> null
9267 + 3750 -> null

这是我的DoubleKey实现:

public class DoubleKey<K extends Comparable<K>,J extends Comparable<J>> implements Comparable<DoubleKey<K,J>>{

    private K key1;
    private J key2;

    public DoubleKey(K key1, J key2){
        this.key1 = key1;
        this.key2 = key2;
    } 

    public K getFirstKey(){
        return this.key1;
    }

    public J getSecondKey(){
        return this.key2;
    }

    // need for Comparable interface
    public int compareTo(DoubleKey<K,J> aThat){
        // NOTE: check for nulls
        return (this.key1.toString() + this.key2.toString()).compareTo(aThat.key1.toString() + aThat.key2.toString());
    }

    public boolean equals(DoubleKey<K,J> aThat){
        return (this.key1.toString() + this.key2.toString()).equals(aThat.key1.toString() + aThat.key2.toString());
    }

}

是怎么回事?如果两个objecst(在这种情况下来自自定义泛型)可以使用2个相同的值进行实例化,那么它们是不同的eve3n吗?我怎么能纠正这个?我希望有人可以帮助我。谢谢!

3 个答案:

答案 0 :(得分:4)

除了.hashCode()之外,你应该有equals(Object)的实现,而不是(仅)equals(DoubleKey<...>),因为否则你将有两个独立的方法(只有第一个是实际上是由HashMap调用的)。这是一个提案:

public boolean equals(Object other) {
    if(this == other)
       return true;
    if(!(other instanceof DoubleKey))
       return false;
    DoubleKey that = (DoubleKey)other;
    return (this.key1 == null ? that.key1 == null : this.key1.equals(that.key1)) &&
           (this.key2 == null ? that.key2 == null : this.key2.equals(that.key2));
}

hashCode方法也应该适合这个,例如:

public int hashCode() {
    return key1.hashCode() * 3 + key2.hashCode() * 5;
}

您的key1.toString()+key2.toString()比较有点危险,因为它允许(1, 21).equals((12,1))为真,这通常不是故意的。 compareTo方法也是如此 - 使用compareTo方法比较组件,而不是连接的字符串。

答案 1 :(得分:3)

立即学习本课程:如果覆盖equals方法(就像你所做的那样),那么你必须覆盖hashcode方法。该方法用于各种事情,包括在HashMaps中查找项目。

答案 2 :(得分:1)

DoubleKey类的hashCode方法在哪里覆盖?我不认为它会作为一个正确的键工作,除非你实现这个,否则你的两个对象将被视为不同。