HashMap源码–(五)Entry
HashMap继承了Map,HashMap.Entry实现了Map.Entry类,并实现了Entry类里的方法。
Entry的实现是一个链表。它的属性包括key、value、next、hash。
HashMap存数据是以key-value的键值对方式,实际HashMap存的是Entry数组,key-value就是Entry对象key和value属性。
Entry类的属性和构造器如下:
static class Entry<K,V> implements Map.Entry<K,V> {
final K key;
V value;
Entry<K,V> next;
final int hash;
/**
* Creates new entry.
*/
Entry(int h, K k, V v, Entry<K,V> n) {
value = v;
next = n;
key = k;
hash = h;
}
}
这里的key是用final定义的,可以看出对于Entry对象来说,key值只能被赋值一次。key也可以赋null。key主要的作用就是用于计算哈希值得出存放位置,使数据快速存取。上面说了HashMap中存放的就是Entry,那在HashMap在存值时,由于key值是final的,不能再次被赋值,所以会先匹配key值是否存在,如果存在,则key对应的Entry对象的value将被覆盖,如果不存在,则创建Entry对象。HashMap取值时,根据key来取值的方式最常用。
Entry类中包含了获取key和value的方法,也包括equals、hashCode、toString,Entry还有两个没有方法内容的方法,如下:
public final K getKey() {return key;}
public final V getValue() {return value;}
public final V setValue(V newValue) {
V oldValue = value;
value = newValue;
return oldValue;
}
public final boolean equals(Object o) {
if (!(o instanceof Map.Entry))
return false;
Map.Entry e = (Map.Entry)o;
Object k1 = getKey();
Object k2 = e.getKey();
if (k1 == k2 || (k1 != null && k1.equals(k2))){
Object v1 = getValue();
Object v2 = e.getValue();
if (v1 == v2 || (v1 != null && v1.equals(v2)))
return true;
}
return false;
}
public final int hashCode() {
return (key==null ? 0 : key.hashCode()) ^
(value==null ? 0 : value.hashCode());
}
public final String toString() {return getKey() + "=" + getValue();}
/**
* 该方法用于key值存在,value被覆盖时
*/
void recordAccess(HashMap<K,V> m) {}
/**
* 该方法用于entry被移除时
*/
void recordRemoval(HashMap<K,V> m) {}
对Entry操作的方法有addEntry、createEntry等,这些操作方法可以看出Entry链表的存储方式,如下:
/**
*添加Entry
*/
void addEntry(int hash, K key, V value, int bucketIndex) {
//在Entry数组table中获取bucketIndex位置的数据
Entry<K,V> e = table[bucketIndex];
//向table数组bucketIndex位置添加Entry对象
table[bucketIndex] = new Entry<K,V>(hash, key, value, e);
//调整数组大小
if (size++ >= threshold)
resize(2 * table.length);
}
/**
*创建Entry
*/
void createEntry(int hash, K key, V value, int bucketIndex) {
//在Entry数组table中获取bucketIndex位置的数据
Entry<K,V> e = table[bucketIndex];
//向table数组bucketIndex位置添加Entry对象
table[bucketIndex] = new Entry<K,V>(hash, key, value, e);
size++;
}
addEntry放在put方法添加数据时使用,是根据给定的key、value、hash添加到Entry数组table的bucketIndex位置。要向数组中加数据,这个方法也需要负责resize数组的大小length。当然如果想改变HashMap的put数据的方式,需要重写这个方法。table[bucketIndex] = new Entry<K,V>(hash, key, value, e);
这段代码是向table数组加Entry对象,这个Entry的next指向table数组的bucketIndex位置。
createEntry同addEntry很像,但它只是向数组赋值,不调整大小。在HashMap构造器使用。