为什么Java Map <K,V>为get和remove方法采用无类型参数?

Mic*_*ick 13 java generics api

我在我的代码中遇到了一个错误,我使用了错误的密钥从Java地图中获取了一些我认为使用Java泛型强类型的东西.在查看Map Javadocs时,许多方法(包括get和remove)都将Object作为参数而不是类型K(对于定义为Map的Map).为什么是这样?有一个很好的理由还是API设计缺陷?

Jim*_*Jim 5

我认为这是为了向后兼容旧版本的 Map 接口。不幸的是,情况确实如此,但正如你是对的,如果采用正确的类型,那就更好了。

  • 哎哟!我强烈不同意这种理由 - 我认为如果您想要一个可以将不同类型用作有效键的用例,那么创建覆盖或限制使用的额外方法。这样,您就拥有了一个强类型的、记录清晰的界面,可以指示预期的用途。在我看来,任何使用对象参数的泛型都表明设计不佳。这种设计使自己面临潜在的危险情况。 (4认同)

jar*_*bjo 5

因为如果传递给 get 方法的对象等于映射中存储的任何键,映射就会返回一个值。相等并不意味着它们必须是相同的类型,而是指键和传递的对象的 equal 方法以这样的方式实现,即不同的对象类型相互识别为相等。

当然,这同样适用于删除方法。


有效代码示例,如果 get 方法仅允许 K 类型的参数,则该代码将中断(无法编译):

LinkedList<Number> k1 = new LinkedList<Number>();
k1.add(10);

ArrayList<Integer> k2 = new ArrayList<Integer>();
k2.add(10);

Map<LinkedList<Number>, String> map = new HashMap<LinkedList<Number>, String>();

map.put(k1, "foo");
System.out.println(map.get(k2));
Run Code Online (Sandbox Code Playgroud)

  • 虽然这在理论上可能是正确的,但使用 equals() 和 hashcode() 实现创建多个以这种方式工作的类将是一个极其丑陋的黑客行为。在我看来,这些方法被定义为将对象作为参数,这样人们就可以编写这样的代码,这似乎不太可能。 (4认同)
  • @Luke Hutterman:查看 List 接口的 equals 方法的文档。它的合同规定,如果两个列表都是列表,并且它们的元素以相同的顺序相同,则它们应该相等,无论列表的类如何。与Set和Map接口相同 (2认同)
  • 即使您认为它很丑,这正是 API 文档中定义 Map 接口和 Object#equals 方法的方式。将泛型添加到 Map 接口时,必须注意不要更改接口方法的已定义行为。强制 get 方法的参数实际上与通用 K 类型具有相同的类型将是对接口定义的非向后兼容的更改。 (2认同)