hashCode()
/**
* @return a hash code value for this object.
* @see java.lang.Object#equals(java.lang.Object)
* @see java.lang.System#identityHashCode
*/
public native int hashCode();
Object源码的hashCode()调用本地方法(c语言编写)利用对象内存地址生成散列码。
equal()
/**
* @param obj the reference object with which to compare.
* @return {@code true} if this object is the same as the obj
* argument; {@code false} otherwise.
* @see #hashCode()
* @see java.util.HashMap
*/
public boolean equals(Object obj) {
return (this == obj);
}
Object的equal()方法比较两个对象的内存地址(是否是同一个引用,同一个对象)
HashMap的get(Object key), hash(Object key)
/**
*
* @see #put(Object, Object)
*/
public V get(Object key) {
Node<K,V> e;
return (e = getNode(hash(key), key)) == null ? null : e.value;
}
static final int hash(Object key) {
int h;
return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
}
可以看到HashMap中根据键获取值会用到键的值和键的hash码,key.hashCode() 根据key对象的内存地址生成hash码,因此不同的key对象即使值一样,但hash码也可能不一样(此时就需要重写hashCode()方法使自定义键类的对象值相同时hash码也要相同,比如直接重写hashCode()使其返回键对象的值,这样就能保证自定义的键在值相同时,hash码也是相同的)
/**
* Implements Map.get and related methods.
*
* @param hash hash for key
* @param key the key
* @return the node, or null if none
*/
final Node<K,V> getNode(int hash, Object key) {
Node<K,V>[] tab; Node<K,V> first, e; int n; K k;
if ((tab = table) != null && (n = tab.length) > 0 &&
(first = tab[(n - 1) & hash]) != null) {
//先比较hash码,再比较键值
if (first.hash == hash && // always check first node
((k = first.key) == key || (key != null && key.equals(k))))
return first;
if ((e = first.next) != null) {
if (first instanceof TreeNode)
return ((TreeNode<K,V>)first).getTreeNode(hash, key);
do {
if (e.hash == hash &&
((k = e.key) == key || (key != null && key.equals(k))))
return e;
} while ((e = e.next) != null);
}
}
return null;
}
getNode(int hash, Object key)方法先比较key的hash码,再比较key的值,两者相等才返回键值对。
这里有个测试类,在没重写Key类的hashCode()时map2.get(k2)获取的值为null
import java.util.HashMap;
import java.util.Map;
public class MapTest {
public static void main(String[] args) {
Map<String,Value> map1 = new HashMap<String,Value>();
String s1 = new String("key");
String s2 = new String("key");
Value value = new Value(2);
map1.put(s1, value);
System.out.println("s1.equals(s2):"+s1.equals(s2));
System.out.println("map1.get(s1):"+map1.get(s1));
System.out.println("map1.get(s2):"+map1.get(s2));
Map<Key,Value> map2 = new HashMap<Key,Value>();
Key k1 = new Key("A");
Key k2 = new Key("A");
map2.put(k1, value);
System.out.println("k1.equals(k2):"+s1.equals(s2));
System.out.println("map2.get(k1):"+map2.get(k1));
System.out.println("map2.get(k2):"+map2.get(k2));
}
/**
* 键
* @author zejian
*
*/
static class Key{
private String k;
public Key(String key){
this.k=key;
}
@Override
public boolean equals(Object obj) {
if(obj instanceof Key){
Key key=(Key)obj;
return k.equals(key.k);
}
return false;
}
}
/**
* 值
* @author zejian
*
*/
static class Value{
private int v;
public Value(int v){
this.v=v;
}
@Override
public String toString() {
return "类Value的值-->"+v;
}
}
输出为
s1.equals(s2):true
map1.get(s1):类Value的值-->2
map1.get(s2):类Value的值-->2
k1.equals(k2):true
map2.get(k1):类Value的值-->2
map2.get(k2):null
为Key类重写HashCode()方法后再运行
@Override
public int hashCode() {
//String 类已经重写过hashCode()使 相同字符串拥有相同的hash码
return k.hashCode();
}
输出结果
s1.equals(s2):true
map1.get(s1):类Value的值-->2
map1.get(s2):类Value的值-->2
k1.equals(k2):true
map2.get(k1):类Value的值-->2
map2.get(k2):类Value的值-->2
此时map2.get(k2)能够获取k1存储的值。