Java面试题:HashMap中当key为类时的注意事项

HashMap中,当key为类时,比较key是否相等需要重写equal() 和hashCode()这两个方法。

在HashMap中,如果key为类对象,则必须要重写hashCode() 和equal()这两个方法。Why?首先了解下未被重写的hashCode() 和equal()方法。

1.未被重写的hashCode() 和equal()方法

public int hashCode():HashCode是根类Obeject中的方法。默认情况下,Object中的hashCode() 返回对象的32位jvm内存地址。也就是说如果对象不重写该方法,则返回相应对象的32为JVM内存地址。 

public bollean equals():用于比较两个对象是否相同,它其实就是使用两个对象的内存地址在比较。Object类中的equals方法内部使用的就是==比较运算符。

2.在HashMap中,判断两个对象(key)是否相等的规则:

2.1.判断两个对象的hashCode()是否相等

如果不相等,认为两个对象也不相等,完毕

如果相等,转入2

2.2.判断两个对象的equals()是否相等

如果不相等,认为两个对象也不相等

如果相等,认为两个对象相等

3.为什么重载hashCode方法?

一般的地方不需要重载hashCode(),只有当类需要放在HashTable、HashMap、HashSet等等hash结构的集合时才会重载hashCode(),那么为什么要重载hashCode()呢?

如果不重载hashCode()方法,由于两个对象实例的内存地址不同,根据2.1,则判为不等。

重载之后,hashCode()方法变成判断其逻辑上是否相同,根据2.1,则判为相等。

4.为什么要重载equal方法?

因为Object的equal方法默认是两个对象的引用的比较,意思就是指向同一内存,地址则相等,否则不相等;如果你现在需要利用对象里面的值来判断是否相等,则重载equal方法。

5.代码示例

假设SysConfig是要作为hashmap的key的一个类

引申扩展:为什么hashmap里的key经常使用string,并且不需要重写hashcode和equals方法?

在《Java 编程思想》中有这么一句话:设计 hashCode() 时最重要的因素就是对同一个对象调用 hashCode() 都应该产生相同的值。String 类型的对象对这个条件有着很好的支持,因为 String 对象的 hashCode() 值是根据 String 对象的内容计算的,并不是根据对象的地址计算。

下面是 String 类源码中的 hashCode() 方法:String 对象底层是一个 final 修饰的 char 类型的数组,hashCode() 的计算是根据字符数组的每个元素进行计算的,所以内容相同的 String 对象会产生相同的散列码。

我们希望的是我们在用对象作为 key 时,我们在获取的时候也依然能够根据重新定义 key 获得对应的 value。就像下面这样,但是它却不能正常工作:这两个对象产生的散列码是不同的,所以在进行 equals() 判断的时候这两个对象被认定为是不同的对象,自然也就获取不到对应的 value。

如果你想获得 map 中存储的“123”,那么你只有把 test 对象作为 key 才能获取到,我们试图用一种简单的方法就能让它工作,但是这显然与我们的初衷相背驰。所以非 String 类型的数据类型在判断 key 相同时所需要的条件太过苛刻。

输出 null

但是 String 类型的对象就不一样了,内容相同的两个 String 对象具有相同的散列码,并且经过 equals() 判断后返回值为 true,所以在进行查找的时候它可以正常工作。

输出 123

总结:在使用 String 类型的对象做 key 时我们可以只根据传入的字符串内容就能获得对应存在 map 中的 value 值,而非 String 类型的对象在获得对应的 value 时需要的条件太过苛刻,首先要保证散列码相同,并且经过 equals() 方法判断为 true 时才可以获得对应的 value。

+3

《Java面试题:HashMap中当key为类时的注意事项》有2个想法

发表评论

您的电子邮箱地址不会被公开。