哈哈!我摊牌了!阿里和美团的面试官都问过我同样的问题,你确定不了解一下?
今天咱们唠点简单的,这是在 初级开发及校招
面试中经常问的一个问题。
给你十秒钟想想你该怎么答... :watch:
想不出来没关系,看了这篇文章后面试遇到同样的问题就是 送分题
。:closed_book:
我们知道Java中所有的类都继承于Object类及Object类是所有类的父类。当子类调用一个方法时,如果该方法没有被重写则需要往上面找到父类中的方法执行。
public boolean equals(Object obj) { return (this == obj); } public native int hashCode(); 复制代码
在Object类中,hashCode是一个本地方法简单理解为 获取对象地址
,equals方法比较自己和obj 对象地址
是否相等。在这里一定先认识到这两个方法,一个是取地址,一个是比较地址。
下面进入正题...
下面以一段小代码演示一下,其输出的结果是 null
。先说一句:在这里我们认为我的a和b是有着相同属性的同一个对象(key),我可以通过hashMap.get(b)获取到字符串 hello。但事与愿违。
public class NoHashCodeAndEquals { public static void main(String[] args) { Object o = new Object(); HashMap<Demo, String> hashMap = new HashMap<>(); Demo a = new Demo("A"); Demo b = new Demo("A"); hashMap.put(a, "hello"); String s = hashMap.get(b); System.out.println(s); } } class Demo { String key; Demo(String key) { this.key = key; } } 复制代码
可能大家一眼看过去感觉没问题,a和b不是同一个对象呀!地址肯定不一样!打住!你在说什么,我刚刚说什么来着 ? :point_up_2: 蒙圈了吧!:dizzy_face:(ps:我自己也快说懵圈了 )。
咱们简单看两行HashMap源码,看完立马就清醒。
static final int hash(Object key) { int h; return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16); } 复制代码
看到了hashCode方法,咱们就还差一个equals方法,HashMap中对于equals()方法的调用在哪些位置呢?
public V put(K key, V value) { ... int hash = hash(key); // 确定桶下标 int i = indexFor(hash, table.length); // 先找出是否已经存在键为 key 的键值对,如果存在的话就更新这个键值对的值为 value for (Entry<K,V> e = table[i]; e != null; e = e.next) { Object k; if (e.hash == hash && ((k = e.key) == key || key.equals(k))) { V oldValue = e.value; e.value = value; return oldValue; } } ... // 插入新键值对 addEntry(hash, key, value, i) return null; } 复制代码
public V get(Object key) { if (key == null) return getForNullKey(); int hash = hash(key.hashCode()); for (Entry<K,V> e = table[indexFor(hash, table.length)]; e != null; e = e.next) { Object k; if (e.hash == hash && ((k = e.key) == key || key.equals(k))) return e.value; } return null; } 复制代码
如上所示:当HashMap调用插入或获取方法,需要将值(key)对应的哈希码与数组中的哈希码比较,相等时,则会通过equals方法比较key值是否相等。
再结合上面我写的代码案例,缓一缓咱们再品一下!
Demo a = new Demo("A"); Demo b = new Demo("A"); 复制代码
这两行的代码的含义,我们理解为定义了两个 相同含义
(认为是同一个key)的key对象,但是大家都知道这两个key的hashcode方法的值是不一样的。
在HashMap中的比较key是这样的,先求出key的hashcode(),比较其值是否相等,若相等再比较equals(),若相等则认为他们是相等的。若equals()不相等则认为他们不相等。
所以想以对象作为HashMap的key, 必须重写该对象的hashCode和equals方法 。确保hashCode相等的时候equals的值也是true。
对于这个问题看似简单,可很多初级程序员竟然说不出一个所以然,一方面是对HashMap不熟悉另外就是对这两个方法的含义理解不透彻。
最后再次总结一句:在HashMap的“键”部分存放自定义的对象, 一定
要重写 equals
和 hashCode
方法。再来两句老生常谈的话!
自己再品品呢 ~