好久不见,最近我要复习了,随时准备面试,顺便整理笔记,所以这又是一篇没有感情的纯物理输出!!!
正文
这一看就是HashMap结构不用说了吧
学会扒系统层源码
HashMpa源码分析
这里,我尝试抛弃1.8之前都源码分析,技术在进步,从现在开始分析1.8之后的版本区别。
结构:数组+链表 位于java.util包中
public class HashMap<K,V> extends AbstractMap<K,V>
implements Map<K,V>, Cloneable, Serializable
静态内部类实现了map的接口,允许使用null值,null键。
JDK 1.8采用的是Node链表
/**
* Basic hash bin node, used for most entries. (See below for
* TreeNode subclass, and in LinkedHashMap for its Entry subclass.)
*/
static class Node<K,V> implements Map.Entry<K,V> {
final int hash;
final K key;
V value;
Node<K,V> next;
Node(int hash, K key, V value, Node<K,V> next) {
this.hash = hash;
this.key = key;
this.value = value;
this.next = next;
}
public final K getKey() { return key; }
public final V getValue() { return value; }
public final String toString() { return key + "=" + value; }
public final int hashCode() {
return Objects.hashCode(key) ^ Objects.hashCode(value);
}
public final V setValue(V newValue) {
V oldValue = value;
value = newValue;
return oldValue;
}
public final boolean equals(Object o) {
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;
}
}
hashmap就是一个entry的数组,entry对象中包含了 key 和 value,其中 next 是为了解决 hash 冲突构成的一个链表。
负载因子:0.75。
static final float DEFAULT_LOAD_FACTOR = 0.75f;
public HashMap() {
this.loadFactor = DEFAULT_LOAD_FACTOR; // all other fields defaulted
}
HashMap中的数据量 / HashMap的总容量(initialCapacity),
当loadFactor达到指定值或者0.75时候,HashMap的总容量自动扩展一倍,以此类推。
负载因子代表了hash表中元素的填满程度。加载因子越大,填满的元素越多,但是冲突的机会增大了,链表越来越长,查询速度会降低。反之,如果加载因子过小,冲突的机会减小了,但是hash表过于稀疏。冲突越大,查找的成本就越高。
数组大小初始值
/**
* The default initial capacity - MUST be a power of two.
*/
static final int DEFAULT_INITIAL_CAPACITY = 1 << 4; // aka 16
数组Node的初始化值是16,使用位与运算是速度更快。
HashMap最大容量
static final int MAXIMUM_CAPACITY = 1 << 30;
必须是2的幂且小于2的30次方,传入容量过大将被这个值替换)
当看到 1<<30 时,对“<<” 有点模糊,当了解“<<”的用法之后,又有一个问题;
int类型不是4个字节共32位吗,为什么不是 1<<31呢?
首先介绍下等号右边数字及字符的含义:
1、"<<"为左移运算符,1表示十进制中的“1”,30表示