0. 成员变量
首先我们先看一下 HashMap 有哪些成员变量
/**
* 默认的初始大小,16,值必须是 2 的幂值
*/
static final int DEFAULT_INITIAL_CAPACITY = 1 << 4; // aka 16
/**
* 最大值,必须是 2 幂值且 小于等于 2 的30 次幂
*/
static final int MAXIMUM_CAPACITY = 1 << 30;
/**
* 默认加载因子,0.75,就是map里的元素值超过 75% 就会触发扩容
*/
static final float DEFAULT_LOAD_FACTOR = 0.75f;
//下面还有三个树化的参数
//如果哈希值相同的元素超过 8 个,则树化
static final int TREEIFY_THRESHOLD = 8;
//树的节点小于 6 个,则转成链表
static final int UNTREEIFY_THRESHOLD = 6;
//如果 map 的元素小于 64,即便是 哈希值相同的元素超过 8 个了,也不树化,会扩容
static final int MIN_TREEIFY_CAPACITY = 64;
复制代码
下面还有一个 Node 类,这个类就是 HashMap 存储元素的容器,其实很简单
static class Node<K,V> implements Map.Entry<K,V> {
final int hash;
final K key;
V value;
Node<K,V> next;
//... ...
}
复制代码
没有多少复杂的内容,类似于链表的Node节点,key、value、next,因为大量的地方都需要用到对象的 hash 值,所以又记录了下 key 的 hash 值。
1. hash()
继续往下看
//求 key 的哈希值
static final int hash(Object key) {
int h;
return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
}
复制代码
也没什么好说的,就是通过对象的 hashCode 计算出一个 int 值。
2. comparableClassFor()
下面有个 comparableClassFor 方法,这个方法的主要是判断入参 x 是否实现了 Comparable 接口。不过写的格式有点紧凑,我们需要展开以下。
static Class<?> myComparableClassFor(Object x) {
if (x instanceof Comparable) {
Class<?> c = x.getClass();
// 获取 x 实现的所有接口
Type[] ts = c.getGenericInterfaces();
Type[] as;
Type t;
ParameterizedType p;
//如果 x 是 String 类型 直接返回
if (c == String.class) {
return c;
}
if (ts != null) {
// 遍历实现的所有接口
for (int i = 0; i < ts.length; ++i) {
t = ts[i];
// 如果接口有泛型
if (t instanceof ParameterizedType) {
p = (ParameterizedType) t;
// 如果泛型对象是 Comparable
if (p.getRawType() == Comparable.class) {
as = p.getActualTypeArguments();
// 只有一个泛型参数,且参数类型是 x.class
if (as != null && as.length == 1 && as[0] == c) {
return c;
}
}
}
}
}
}
return null;
}
复制代码
举个例子:
class MyTest implements Comparable<MyTest> {}
会返回 MyTest.class
class MyTest implements Comparable<Integer> {}
会返回 null
复制代码
这个方法就结束了,如果还是不能理解,可以将代码复制出来,打个断点跑一下。继续往下看。
@SuppressWarnings({"rawtypes","unchecked"}) // for cast to Comparable
static int compareComparables(Class<?> kc, Object k, Object x) {
return (x == null || x.getClass() != kc ? 0 :
((Comparable)k).compareTo(x));
}
复制代码
这个方法有意思,注释是说,如果 x 是 kc 的类型,返回 k.compareTo(x) (k 是筛选过的比较类)。如果你查找下这个方法的使用地方就会发现,kc 这个参数就是上面 comparableClassFor 返回的类型。
这么一看是不是就清晰了? comparableClassFor(x) 拿到类型,然后传入 compareComparables(kc,k,x) 去比较。
3. tableSizeFor()
下面又是一个方法:
static final int tableSize