java - 自定义通用类作为 HashMap 问题的关键

标签 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);
}

我所做的是创建一个自定义通用类 DoubleKey 来包含具有两部分的 key 。正如您所看到的,Set s 和 HashMap hm 的键具有相同的组件,但实例化方式不同(k1 = k2) 。当我尝试使用 shm 上的键获取一个值时,它返回 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());
    }

}

这是怎么发生的?如果两个对象(在本例中来自自定义泛型)使用 2 个相同的值实例化,它们是否可以不同?我该如何纠正这个问题?我希望有人能在这里帮助我。谢谢!

最佳答案

除了 .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 方法比较组件,而不是连接的字符串。

关于java - 自定义通用类作为 HashMap 问题的关键,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5057504/

相关文章:

javascript - es6 Map 和 Set 复杂度,v8 实现

java - 如何根据条件有选择地从数组列表中删除值?

java - 如何在Android开发环境中添加非Android的Java包?

algorithm - 集合中互斥项的子集

java - Guava Sets.difference#isEmpty() 行为

具有泛型的Scala类型类

java - 是否可以在 IntelliJ Idea 中超链接评论?

java - java中printf和println的区别?

java - 与 Arrays.asList() 不兼容的类型

c# - 是否可以对泛型方法进行不安全的协变调用?