由于HashMap的存储数据的特点是 : 无序,无索引,不能存储重复元素,所以这里容易想到的是类的HashCode()函数
HashMap是利用HashCode()来区别两个不同的对象。
而HashCode()是本地方法,是用C或C++来实现的,即该方法是直接返回对象的内存地址。
public V put(K key, V value) {
if (key == null)
return putForNullKey(value); //判断key是否为null 是则默认给个NullKey
int hash = hash(key); //根据 key 计算出 hashcode
int i = indexFor(hash, table.length); //根据计算出的 hashcode 定位出所在桶。
for (Entry<K,V> e = table[i]; e != null; e = e.next) {
//如果桶是一个链表则需要遍历判断里面的 hashcode、key 是否和传入 key 相等,如果相等则进行覆盖,并返回原来的值。
Object k;
if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {
V oldValue = e.value;
e.value = value;
e.recordAccess(this);
return oldValue;
}
}
modCount++;
//如果桶是空的,说明当前位置没有数据存入;新增一个 Entry 对象写入当前位置
addEntry(hash, key, value, i);
return null;
}
void addEntry(int hash, K key, V value, int bucketIndex) {
if ((size >= threshold) && (null != table[bucketIndex])) {
resize(2 * table.length);
hash = (null != key) ? hash(key) : 0;
bucketIndex = indexFor(hash, table.length);
}
createEntry(hash, key, value, bucketIndex);
}
void createEntry(int hash, K key, V value, int bucketIndex) {
Entry<K,V> e = table[bucketIndex];
table[bucketIndex] = new Entry<>(hash, key, value, e);
size++;
}
而基础类型里面没有hashcode()方法,而且不能设置为null,所以不允许HashMap中定义基础类型的key,而value也是不能定义为基础类型。在Java中是使用泛型来约束HashMap中的key和value的类型的,即HashMap< K, V>;而泛型在Java的规定中必须是对象Object类型的,因为基础类型并没有继承object类,所以无法使用。
而在HashMap存储自定义对象的时候,需要自己再自定义的对象中重写其hashCode()方法和equals方法,才能保证其存储不重复的元素。
否则将存储多个重复的对象,因为每new一次,其就创建一个对象,内存地址是不同的。由于我们是只想看两个对象的某个属性是否相同来判断是否相同,所以就会出先找不到的情况,即返回hull。因为我们没有重写,他就会使用默认的hashcode()。对比的是两个对象的虚拟内存地址,而两个不同的对象,他们的内存地址是不一致的,所以就会返回为NULL。