决定在java.util.Map<K, V>
接口中没有完全通用的get方法的背后原因是什么?
为了澄清问题,该方法的签名是
V get(Object key)
代替
V get(K key)
我想知道为什么(与remove, containsKey, containsValue
)。
#1楼
这是Postel法则的一种应用, “对您的工作要保守,对别人接受的东西要宽松”。
不论类型如何,都可以执行相等性检查。 equals
方法在Object
类上定义,并接受任何Object
作为参数。 因此,对于密钥等效性以及基于密钥等效性的操作来说,接受任何Object
类型都是有意义的。
映射返回键值时,通过使用type参数,它可以保存尽可能多的类型信息。
#2楼
还有一个重要的原因,因为它破坏了Map,因此在技术上无法完成。
Java具有像<? extends SomeClass>
<? extends SomeClass>
。 标记为此类引用可以指向使用<AnySubclassOfSomeClass>
签名的类型。 但是多态泛型使该引用变为只读 。 编译器仅允许您将泛型类型用作方法的返回类型(如简单的getter),但会阻止使用泛型为参数的方法(如普通的setter)。 这意味着您是否编写Map<? extends KeyType, ValueType>
Map<? extends KeyType, ValueType>
,编译器不允许您调用方法get(<? extends KeyType>)
,该映射将无用。 唯一的解决方案是使此方法不通用: get(Object)
。
#3楼
我看着这个,想着为什么他们要这样做。 我不认为任何现有答案都可以解释为什么它们不能仅使新的通用接口仅接受密钥的正确类型。 实际原因是,即使他们引入了泛型,他们也没有创建新接口。 Map接口与旧的非通用Map相同,仅用作通用和非通用版本。 这样,如果您有一个接受非通用Map的方法,则可以将Map<String, Customer>
传递给它,它仍然可以工作。 同时,获取合同接受对象,因此新接口也应支持该合同。
在我看来,他们应该添加一个新接口并在现有集合上都实现,但是他们决定支持兼容接口,即使这意味着对get方法进行更糟糕的设计。 请注意,集合本身将与现有方法兼容,仅接口不兼容。
#4楼
我们现在正在进行大型重构,并且缺少此强类型的get()来检查我们是否没有丢失旧类型的某些get()。
但是我发现了一种用于编译时间检查的解决方法/丑陋技巧:使用强类型的get,containsKey,remove ...创建Map接口,并将其放入项目的java.util包中。
您将因为仅使用错误的类型调用get()而得到编译错误,...对于编译器而言,其他一切似乎都正常(至少在eclipse kepler内部)。
检查构建后,不要忘记删除此接口,因为这不是运行时所需的。
#5楼
兼容性。
在泛型可用之前,只有get(Object o)。
如果他们将这种方法更改为get(<K> o),可能会迫使对Java用户的大规模代码维护只是为了使工作代码再次编译。
他们本可以引入另一种方法,例如说get_checked(<K> o)并弃用旧的get()方法,以便有一条更平缓的过渡路径。 但是由于某种原因,这没有完成。 (现在的情况是,您需要安装诸如findBugs之类的工具,以检查get()参数与地图的声明键类型<K>之间的类型兼容性。)
我认为与.equals()的语义有关的参数是虚假的。 (从技术上讲,它们是正确的,但我仍然认为它们是虚假的。如果o1和o2没有任何共同的超类,那么在他的脑海中就不会有任何设计师能够使o1.equals(o2)为真。)
来源:oschina
链接:https://my.oschina.net/stackoom/blog/3164295