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

简介: 帮别人的代码改bug,发现有一大堆bug是由get或者remove传递进去的参数类型不匹配而造成的。比如: Map m = new HashMap(); m.put(new Short((short) 2), "2222"); System.out.println(m.get(2));上面的代码输出是null。

帮别人的代码改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


相关文章
|
1月前
|
JavaScript 前端开发 Java
Java Script中的函数原型是什么
Java Script中的函数原型是什么
11 0
|
2月前
|
存储 Java 索引
JAVA零基础小白学习免费教程day14-Set&HashMap(一)
JAVA零基础小白学习免费教程day14-Set&HashMap
97 0
|
12天前
|
Java 存储
键值之道:深入学习Java中强大的HashMap(二)
键值之道:深入学习Java中强大的HashMap
20 0
键值之道:深入学习Java中强大的HashMap(二)
|
1月前
|
Java 数据库连接 API
Java 学习路线:基础知识、数据类型、条件语句、函数、循环、异常处理、数据结构、面向对象编程、包、文件和 API
Java 是一种广泛使用的、面向对象的编程语言,始于1995年,以其跨平台性、安全性和可靠性著称,应用于从移动设备到数据中心的各种场景。基础概念包括变量(如局部、实例和静态变量)、数据类型(原始和非原始)、条件语句(if、else、switch等)、函数、循环、异常处理、数据结构(如数组、链表)和面向对象编程(类、接口、继承等)。深入学习还包括包、内存管理、集合框架、序列化、网络套接字、泛型、流、JVM、垃圾回收和线程。构建工具如Gradle、Maven和Ant简化了开发流程,Web框架如Spring和Spring Boot支持Web应用开发。ORM工具如JPA、Hibernate处理对象与数
92 3
|
1月前
|
存储 安全 Java
Java HashMap 和 HashSet 的高效使用技巧
HashMap 是一种哈希表,它存储键值对。键用于查找值,就像数组中的索引一样。HashMap 的优势在于它可以使用任何类型作为键,并且查找速度很快。
64 1
|
2月前
|
存储 Java 索引
【Java编程进阶之路 03】深入探索:HashMap的长度为什么是2的幂次方
HashMap的长度为2的幂次方是为了利用位运算快速计算索引,提高数据分散性和减少哈希冲突。这样设计能确保元素均匀分布,提高搜索效率。同时,2的幂次方长度便于动态扩容时计算新位置,简化元素迁移过程。
|
2月前
|
存储 并行计算 安全
【Java编程进阶之路 01】深入探索:HashMap、ConcurrentHashMap与HashTable的演进之路
HashMap、ConcurrentHashMap与HashTable均为Java中的哈希表实现。HashMap非线程安全但性能高,适用于单线程;HashTable线程安全但性能较低,已少用;ConcurrentHashMap线程安全且高性能,是并发环境下的首选。三者在线程安全性与性能间各有侧重。
|
2月前
|
Java 流计算
在Flink实时任务中,POJO(Plain Old Java Object)对象的模式演进可能会引起不兼容的问题
【2月更文挑战第6天】在Flink实时任务中,POJO(Plain Old Java Object)对象的模式演进可能会引起不兼容的问题
19 3
|
2月前
|
存储 缓存 安全
Java HashMap:哈希表原理、性能与优化
Java HashMap:哈希表原理、性能与优化
|
2月前
|
Java
JAVA零基础小白学习免费教程day14-Set&HashMap(三)
JAVA零基础小白学习免费教程day14-Set&HashMap
37 0