我正在寻找有关如何使用Interface作为Maps Key的主题的帮助。我尝试实现一个解决方案,并且在运行集成测试时没有编译时错误但是运行时错误。是否无法将接口用作密钥,或者我的测试是否存在问题?
我的代码看起来像这样
private Map<AInterface, Values> myMap = new HashMap<AInterface, Values>();
从myMap中检索一组键时,它们确实包含具有预期Id的对象,但是被比较为不相等。因此,当使用myMap.get(Object key)时,我得到null,尽管有一个具有相同id的对象。当使用具体类而不是接口时,所有测试都通过:
private Map<AClass, Values> myMap = new HashMap<AClass, Values>();
我已阅读Generics,其中声明对于Map,您需要使用Object的子类型的具体类型替换类型变量K和V.
由于编译器在使用K接口时没有给我任何警告,我的猜测是测试有错误。
是否有人在使用Interfaces作为地图中的键时有任何经验?可以给我任何关于我做错的提示吗?
答案 0 :(得分:5)
您的课程必须实施hashCode
和equals
(explanation;您还应该熟悉contract of the Map-interface)。
答案 1 :(得分:2)
扩展界面的对象应该同时实现hashCode
和equals
。如果equals
返回true
但hashCode
值不相等,则找不到相应的对象,因为JVM将对象放在“桶”中(存储在{{1}中时) })根据他们的Map
值。
答案 2 :(得分:0)
两个例子都应该完美无缺。在'泛型'中使用接口,抽象或具体类类型是可以的。我经常在地图中使用List界面,从来没有遇到过问题。
您说您只需更改myMap
的类型和构造函数以使测试通过?您在地图中使用哪种类型的对象AClass
或其他?
仔细查看运行时错误或向我们提供一些细节(只是没有堆栈跟踪的例外情况)。
对于另一个问题,正如Wesho已经回答的那样,在你真正用于地图中的键的类中实现hashcode和equals或者(用于测试)它们中的任何一个。
修改强>
从评论中了解到,哈希码和等号已经实现:有一个可能的陷阱 - 如果你在之后更改了UUID ,那么对象已经被放到了地图上(作为一个键),那么你之后可能无法找到您的值(尽管地图上的重新渲染会使其再次起作用)。
编辑2
如果您直接在myMap.get(AClass key)
上收到NPE,则myMap
为null
或密钥(但仍然无法解决其他问题......)
编辑3
刚刚检查了UUID上的hashcode和equals的实现,那没关系。计算仅限于128位UUID。因此,如果为相同的UUID值创建两个UUID对象并测试相等性,则两个UUID对象不相同但相等。非常好。如果您在AClass中使用了UUID的getter,那么您将尝试使用类似HashMap<UUID, Values> myMap
的Map并检查它是否仍然有效(可能,代码更改取消隐藏真正的错误;)
答案 3 :(得分:0)
[...]它声明对于地图,你 需要更换类型 变量K和V由具体类型决定 这是Object的子类型。
我接近问了一个问题,但我想我已经得到了答案。
具体类型 - 听起来有点像'具体类',好像不允许使用接口或抽象类。但它只是说,你不允许用另一种通用类型'S'代替'K'。它必须是一个“真正的”类型:接口,类,甚至枚举都足够具体。
对象的子类型 - 再次听起来像是不允许接口,因为它们不是Object的子类。是的,但是:无论如何都无法实例化接口,因此放入地图的真实对象是始终类实例。不是Object子类的唯一Java类型是Java原语,包括Java原语数组。因此,Map<int, String>
不允许以及。Map<String, int[]>
答案 4 :(得分:0)
问题与接口无关。通用类型在编译时被擦除,并且在运行时HashMap仅处理对象实例。
我们无法知道您的问题是什么,因为您没有显示任何代码,但最有可能的是您的密钥是可变的并且您的hashCode正在发生变化。
例如:
class MyKey {
String name;
public int hashCode() {
return name.hashCode();
}
// assume suitable equals() implementation
}
Map<MyKey,Integer> myMap = new HashMap();
MyKey key1 = new MyKey();
key1.name = "Jimmy";
myMap.put(key1, 10);
key1.name = "Johnny";
myMap.get(key1); // return null
如果对象的哈希码在添加到地图和尝试检索它之间发生变化,那么HashMap(可能)会查找错误的哈希桶,而不会找到任何值。如果旧的哈希码和新的哈希码解析为相同的哈希桶,有时可能会得到结果。
答案 5 :(得分:-1)
如果您正在使用Apache Commons lang JAR,可以将其添加到您的班级。
public int hashCode() {
return HashCodeBuilder.reflectionHashCode(this);
}