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

简介:

帮别人的代码改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天前
|
Java
用java搞定时任务,将hashmap里面的值存到文件里面去
本文介绍了如何使用Java的`Timer`和`TimerTask`类创建一个定时任务,将HashMap中的键值对写入到文本文件中,并提供了完整的示例代码。
8 1
用java搞定时任务,将hashmap里面的值存到文件里面去
|
5天前
|
Java
Java Object 类详解
在 Java 中,`Object` 类是所有类的根类,每个 Java 类都直接或间接继承自 `Object`。作为所有类的超类,`Object` 定义了若干基本方法,如 `equals`、`hashCode`、`toString` 等,这些方法在所有对象中均可使用。通过重写这些方法,可以实现基于内容的比较、生成有意义的字符串表示以及确保哈希码的一致性。此外,`Object` 还提供了 `clone`、`getClass`、`notify`、`notifyAll` 和 `wait` 等方法,支持对象克隆、反射机制及线程同步。理解和重写这些方法有助于提升 Java 代码的可读性和可维护性。
|
19天前
|
设计模式 Java
结合HashMap与Java 8的Function和Optional消除ifelse判断
`shigen`是一位致力于记录成长、分享认知和留住感动的博客作者。本文通过具体代码示例探讨了如何优化业务代码中的if-else结构。首先展示了一个典型的if-else处理方法,并指出其弊端;然后引入了策略模式和工厂方法等优化方案,最终利用Java 8的Function和Optional特性简化代码。此外,还提到了其他几种消除if-else的方法,如switch-case、枚举行、SpringBoot的IOC等。一起跟随shigen的脚步,让每一天都有所不同!
29 10
结合HashMap与Java 8的Function和Optional消除ifelse判断
|
16天前
|
Java
java基础(11)函数重载以及函数递归求和
Java支持函数重载,即在同一个类中可以声明多个同名方法,只要它们的参数类型和个数不同。函数重载与修饰符、返回值无关,但与参数的类型、个数、顺序有关。此外,文中还展示了如何使用递归方法`sum`来计算两个数之间的和,递归的终止条件是当第一个参数大于第二个参数时。
26 1
java基础(11)函数重载以及函数递归求和
|
7天前
|
存储 安全 Java
Java HashMap详解
`HashSet` 是 Java 中基于哈希表实现的 `Set` 接口集合,主要用于存储不重复元素,提供快速查找、插入和删除操作。它不允许重复元素,不保证元素顺序,但允许一个 `null` 元素。常用操作包括创建、添加、删除、检查元素及清空集合。由于其哈希表结构,`HashSet` 在插入、删除和查找操作上具有常数时间复杂度 O(1),性能高效。适用于需要快速访问和操作的场景,但需注意其无序性和线程安全问题。
|
2月前
|
Java 调度 Android开发
Android经典实战之Kotlin的delay函数和Java中的Thread.sleep有什么不同?
本文介绍了 Kotlin 中的 `delay` 函数与 Java 中 `Thread.sleep` 方法的区别。两者均可暂停代码执行,但 `delay` 适用于协程,非阻塞且高效;`Thread.sleep` 则阻塞当前线程。理解这些差异有助于提高程序效率与可读性。
52 1
|
2月前
|
Java 开发工具
【Azure Developer】Java代码访问Key Vault Secret时候的认证问题,使用 DefaultAzureCredentialBuilder 或者 ClientSecretCredentialBuilder
【Azure Developer】Java代码访问Key Vault Secret时候的认证问题,使用 DefaultAzureCredentialBuilder 或者 ClientSecretCredentialBuilder
|
2月前
|
存储 Java 数据处理
如何使用 Java 迭代 HashMap 中的 ArrayList
【8月更文挑战第23天】
43 2
|
2月前
|
存储 开发者 C#
WPF与邮件发送:教你如何在Windows Presentation Foundation应用中无缝集成电子邮件功能——从界面设计到代码实现,全面解析邮件发送的每一个细节密武器!
【8月更文挑战第31天】本文探讨了如何在Windows Presentation Foundation(WPF)应用中集成电子邮件发送功能,详细介绍了从创建WPF项目到设计用户界面的全过程,并通过具体示例代码展示了如何使用`System.Net.Mail`命名空间中的`SmtpClient`和`MailMessage`类来实现邮件发送逻辑。文章还强调了安全性和错误处理的重要性,提供了实用的异常捕获代码片段,旨在帮助WPF开发者更好地掌握邮件发送技术,提升应用程序的功能性与用户体验。
40 0
|
2月前
|
存储 运维 Java
函数计算产品使用问题之怎么配置定时触发器来调用Java函数
函数计算产品作为一种事件驱动的全托管计算服务,让用户能够专注于业务逻辑的编写,而无需关心底层服务器的管理与运维。你可以有效地利用函数计算产品来支撑各类应用场景,从简单的数据处理到复杂的业务逻辑,实现快速、高效、低成本的云上部署与运维。以下是一些关于使用函数计算产品的合集和要点,帮助你更好地理解和应用这一服务。