如何使用接口作为地图的密钥

时间:2009-11-26 09:03:51

标签: java generics dictionary interface

我正在寻找有关如何使用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作为地图中的键时有任何经验?可以给我任何关于我做错的提示吗?

6 个答案:

答案 0 :(得分:5)

您的课程必须实施hashCodeequalsexplanation;您还应该熟悉contract of the Map-interface)。

答案 1 :(得分:2)

扩展界面的对象应该同时实现hashCodeequals。如果equals返回truehashCode值不相等,则找不到相应的对象,因为JVM将对象放在“桶”中(存储在{{1}中时) })根据他们的Map值。

答案 2 :(得分:0)

两个例子都应该完美无缺。在'泛型'中使用接口,抽象或具体类类型是可以的。我经常在地图中使用List界面,从来没有遇到过问题。

您说您只需更改myMap的类型和构造函数以使测试通过?您在地图中使用哪种类型的对象AClass或其他?

仔细查看运行时错误或向我们提供一些细节(只是没有堆栈跟踪的例外情况)。

对于另一个问题,正如Wesho已经回答的那样,在你真正用于地图中的键的类中实现hashcode和equals或者(用于测试)它们中的任何一个。

修改

从评论中了解到,哈希码和等号已经实现:有一个可能的陷阱 - 如果你在之后更改了UUID ,那么对象已经被放到了地图上(作为一个键),那么你之后可能无法找到您的值(尽管地图上的重新渲染会使其再次起作用)。

编辑2

如果您直接在myMap.get(AClass key)上收到NPE,则myMapnull或密钥(但仍然无法解决其他问题......)

编辑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);
}