Java 强制映射实现的类型参数上的属性(如在接口中)

Java 强制映射实现的类型参数上的属性(如在接口中),java,generics,collections,overriding,type-erasure,Java,Generics,Collections,Overriding,Type Erasure,我想实现Map接口,但将K和V绑定到接口)。但是,考虑到Java collections API,特别是MAP接口,使用Object而不是泛型类型K和V来限制方法参数的最小值。为了举例说明该接口,指定:public boolean containsValue(Object value)而不是public boolean containsValue(V value)。在这种情况下,我不能依赖编译器类型安全性 明确地说,我想实现如下内容: Map<String, Integer> map

我想实现Map接口,但将K和V绑定到接口)。但是,考虑到Java collections API,特别是MAP接口,使用Object而不是泛型类型K和V来限制方法参数的最小值。为了举例说明该接口,指定:
public boolean containsValue(Object value)
而不是
public boolean containsValue(V value)
。在这种情况下,我不能依赖编译器类型安全性

明确地说,我想实现如下内容:

Map<String, Integer> map = new HashMap<>();
String key = "A Key";
Integer value = 1;
map.put(key, value);

Object objectKey = key; // this is the same key object, but it is typed as Object
map.containsKey(objectKey); // what would you want/expect this to return?
map.get(objectKey); // ...or this?
类MyMap实现Map

但是,我需要实现以下方法:

@Override
public boolean containsValue(Object value) {
      // What to do here? 
      ValueInterface v = (ValueInterface ) v; 
      v.getWhatIWant().andDoThing(); 
      // Follow on... 
}
在这种情况下,我有哪些选项和/或最佳做法?

如果要实现
Map
,则需要实现界面中的所有方法


您可以扩展
AbstractMap
并覆盖抽象方法,以及您想要自定义行为的任何非抽象方法(只要您不违反
Map
契约)。

这是
Map
的接口契约-因此,您必须按照现有契约执行

然而,让我提出两个理由,为什么
地图的这一部分的设计是一件好事:

i)
Map
是指您可以在以下情况下从Map中获取值:

如果此映射包含从键k到值v的映射,则 (key==null?k==null:key.equals(k)),则该方法返回v; 否则返回null。(最多可以有一个这样的映射。)

或等效,并针对您关于
containsKey(对象键)
的问题:

如果此映射包含指定键的映射,则返回true。更正式地说,当且仅当此映射包含一个键k的映射,使得(key==null?k==null:key.equals(k))时,返回true。(最多可以有一个这样的映射。)

因此,您关心的不是键入,而是平等性

ii)这确实是同一点,但考虑如下:

Map<String, Integer> map = new HashMap<>();
String key = "A Key";
Integer value = 1;
map.put(key, value);

Object objectKey = key; // this is the same key object, but it is typed as Object
map.containsKey(objectKey); // what would you want/expect this to return?
map.get(objectKey); // ...or this?
请注意,
instanceof
检查基础对象的类型,而不是其声明的类型,因此:

String key = "A Key";
Object objectKey = key;
boolean isString = (objectKey instanceof String); // is true

真的,我建议,与其问如何强制执行违背
Map
合同的东西,不如问这个问题“…

你的第二句话是什么意思?这个问题有一些有趣的答案,关于为什么
Map
接口没有对某些方法参数使用泛型类型:@RohitJain I编辑了这个问题。希望更好地了解。但代码举例说明,由于接口契约,我必须处理一个对象,但我希望V确保我有可能依赖ValueInterface属性。@Anderschuller是的,这是一个有趣的问题和答案。我真的很好奇,但对于这一决定背后的原因似乎没有达成共识。此外,我希望在我的问题背景下看到对该设计的评估。因此,本质上,你的答案是:好吧,你不能做任何事情,除了铸造和希望更好(如果你想实现Map):)不幸的是,是的。
Map
接口最初是在泛型之前设计的,我想更改签名会破坏太多的现有代码。我感觉合同是这样的,因为基于平等的实现。这对我来说很糟糕,因为看起来他们让实现细节泄露到了接口的设计中。然而,在这个问题的具体背景下,我真的不关心这一决定背后的原因。我只是想知道我是否应该:避免实现映射,或者通过强制转换(小心使用instanceof off-course)或其他一些我不知道的通用魔法来解决这个问题。@fabiim-映射接口中的这种设计是一件好事(您应该关心它,因为理解它为什么是一件好事将更好地使您能够在Java中使用泛型)。Java泛型并没有什么神奇之处-它们是语言中非常有用的一部分,尽管需要一些时间和精力来学习/理解。至于您的具体用法,这完全取决于您试图实现的目标……目前您最初的问题是“我想实现映射接口…”,对此(毫不奇怪)您将需要实现Map接口。