[英]Custom Generic Class as Key to Hash Map Issue
I have this following test code: 我有以下测试代码:
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); }
What I did is to create a Custom Generic Class DoubleKey<K, J> to contain a key having two parts. 我所做的是创建一个自定义通用类DoubleKey <K,J>来包含一个包含两部分的键。 As you can see, the Set s and the keys of HashMap hm are have the same components, but was instantiated differently ( k1 = k2 ). 正如你所看到的,集合S和HashMap HM的密钥具有相同的成分,但不同的实例化(K1 = K2)。 When I try to get a value using the keys on s to hm , it returns null , though at the first printing it shows the correct mapping. 当我尝试使用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
This is my DoubleKey implemention: 这是我的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()); } }
How did it happened? 怎么发生的 Can two objecst (in this case from a custom generic) be different eve3n if they have instantiated with 2 same values? 如果两个objecst(在这种情况下是来自自定义泛型)可以用两个相同的值实例化,则它们可以不是eve3n吗? How can I correct this? 我该如何纠正? I hope someone can help me here. 我希望有人可以在这里帮助我。 Thanks! 谢谢!
Additionally to .hashCode()
, you should have an implementation of equals(Object)
, not (only) equals(DoubleKey<...>)
, since otherwise you'll have two independent methods here (and only the first one is actually called by the HashMap). 除了.hashCode()
,您还应该实现equals(Object)
,而不是(仅) equals(DoubleKey<...>)
,因为否则您将在此处拥有两个独立的方法(实际上只有第一个是由HashMap调用)。 Here is a proposal: 这是一个建议:
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));
}
The hashCode method should be made to fit this, too, for example like this: hashCode方法也应适合此情况,例如:
public int hashCode() {
return key1.hashCode() * 3 + key2.hashCode() * 5;
}
Your key1.toString()+key2.toString()
comparison is a bit dangerous, as it lets (1, 21).equals((12,1))
be true, which is usually not intended. 您的key1.toString()+key2.toString()
比较有点危险,因为它使(1, 21).equals((12,1))
为true,通常这是不希望的。 The same is true for your compareTo method - compare the components using their compareTo method, not the concatenated String. 对于compareTo方法也是如此-使用组件的compareTo方法(而不是串联的String)比较组件。
Learn this lesson now: If you override the equals method (as you have done), then you MUST override the hashcode method too. 现在学习本课程:如果您覆盖equals方法(如已完成),那么您也必须覆盖hashcode方法。 That method is used for various things, including looking up items in HashMaps. 该方法用于各种用途,包括在HashMaps中查找项目。
Where is DoubleKey class's hashCode method override? DoubleKey类的hashCode方法在哪里覆盖? I don't think that it will work as a proper key unless you implement this because otherwise your two objects will be considered different. 我认为除非您实现此功能,否则它不能用作适当的键,因为否则您的两个对象将被认为是不同的。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.