为什么Java中的HashMap<K, V>的get函数是get(Object key),而不是get(K key)?

来源:互联网 发布:阿里云ecs是干什么用的 编辑:程序博客网 时间:2024/05/01 07:49

帮别人的代码改bug,发现有一大堆bug是由get或者remove传递进去的参数类型不匹配而造成的。

比如:

Map<Short, String> m = new HashMap();m.put(new Short((short) 2), "2222");System.out.println(m.get(2));

上面的代码输出是null。

一般人很难发现传递进去的int和Short类型不匹配,而且IDE,编译器也没有提示。当然通过一些分析工具可以检查出来。


真的感到很困惑,Java中的容器的一些函数,参数都是Object类型,如HashMap中的get,remove函数,Set中的contains函数。

为什么不明确它们的类型?这样编译器可以检查出类型不匹配的错误。

Google之,google的一个工程师给出了答案:http://smallwig.blogspot.com/2007/12/why-does-setcontains-take-object-not-e.html

为了简单起见,以Set容器为例:

定义一个简单的S,只有一个简单的contains函数:

class S<K>{public void contains(K k){System.out.println("S<K>,contains(K k)");}}

假如我们有个函数,想要处理Foo类的集合:

public void doSomeReading(S<Foo> foos) { }
要是我们想能同时处理Foo类的子类(如SubFoo)的集合,那应该这样定义:

public void doSomeReading(S<? extends Foo> foos) { }

一切看起来很好,但是如果我们把代码都合起来,就会发现悲剧了:

class S<K>{public void contains(K k){System.out.println("S<K>,contains(K k)");}}class Foo{}class SubFoo extends Foo{}public void doSomeReading(S<? extends Foo> foos) { Foo f = new Foo();SubFoo subFoo = new SubFoo();foos.contains(f); //这里eclipse会提示出错,这里只有填null时才不会报错foos.contains(subFoo); //同样错误foos.contains(null);}

这时编译器不干了,它表示不能工作了。

原来在S<K>类的定义中,我们明确contains(K  k)函数只能接受一个明确类型的参数。

但是在doSomeReading函数中,编译器无法确定到底是什么类型,它是Foo类型,还是SubFoo类型,还是SubSubFoo类型?

编译器无从得知,所以它只允许null类型的参数。

===========================================================

对于这个解析,话说还是有点郁闷。

也有另外的解析,认为和equals函数有关系。不过感觉不大靠谱,这个只能说是一些另类的应用。

http://stackoverflow.com/questions/857420/what-are-the-reasons-why-map-getobject-key-is-not-fully-generic


原创粉丝点击