JDK版本为1.8
使用HashMap什么时候需要重写equals方法?
当需要把自己声明的类的对象用作HashMap中的key值时,由于HashMap中get()与put()方法的实现中大量运用了equals方法对key元素的散列与查找进行比较操作,若希望携带自创类型为key或value的HashMap在散列时能够均匀、在存取时能够精准,需要在自己创建的类中重写类的equals方法,进而不去调用Object类的equals方法。
class Person{
private String name;
private String IDcard;
public boolean equals(Person p){
if(this.IDcard!=null || this.IDcard,equals(p.IDcard))
return true;
return false;
}
}
此处只是源码的简单分析,而对于HashMap的详细工作原理,还是要归根结底到get,put等方法的实现
下面是HashMap中的静态内部类Node的equals方法的源码
public final boolean equals(Object o) {
//此处单独比较的是Node
if (o == this)
return true;
if (o instanceof Map.Entry) {
Map.Entry<?,?> e = (Map.Entry<?,?>)o;
if (Objects.equals(key, e.getKey()) &&
Objects.equals(value, e.getValue()))
return true;
}
return false;
}
上面使用的equals
方法是位于Objects
类中(注意不是Object)静态的比较方法:在我看来,这里有为了避免NullPointerException
异常。
public static boolean equals(Object a, Object b) {
return (a == b) || (a != null && a.equals(b));
}
在实际调用equals方法是,HashMap使用父类AbstractMap的equals,下面是AbstractMap中的equals方法:
public boolean equals(Object o) {
//首先判断两个对象的内存地址是否相同,若相同返回true
if (o == this)
return true;
//判断参数是否为Map类或它的子类
if (!(o instanceof Map))
return false;
//判断两个map的size是否相同,size()是同一个类中的方法
Map<?,?> m = (Map<?,?>) o;
if (m.size() != size())
return false;
try {
//使用迭代器遍历调用equal方法的那个map,注意entrySet方法
//m即为上面参数赋值过的那个传入的map对象
Iterator<Entry<K,V>> i = entrySet().iterator();
while (i.hasNext()) {
Entry<K,V> e = i.next();
K key = e.getKey();
V value = e.getValue();
if (value == null) {
//当这个节点的value值为null时,比较key
if (!(m.get(key)==null && m.containsKey(key)))
return false;
} else {
//当节点的值不为空时,比较"调用方法的对象的值"与在"参数对象"中同一key取出的值
if (!value.equals(m.get(key)))
return false;
}
}
} catch (ClassCastException unused) {
return false;
} catch (NullPointerException unused) {
return false;
}
return true;
}
下面顺便说涉及到的一个containsKey方法,源码如下
public boolean containsKey(Object key) {
//此处是一个简单的判断key的过程,首先获取调用此方法的对象的迭代器
Iterator<Map.Entry<K,V>> i = entrySet().iterator();
//当传入key为null时,判断调用对象的key是否为null
if (key==null) {
while (i.hasNext()) {
Entry<K,V> e = i.next();
if (e.getKey()==null)
return true;
}
//当传入key不为null时,判断调用对象的key是否相同,调用的equals就到了Object的,按照不同数据类型的比较方法再次比较
} else {
while (i.hasNext()) {
Entry<K,V> e = i.next();
if (key.equals(e.getKey()))
return true;
}
}
return false;
}