JDK7 HashMap源码分析
本文基于JDK1.7.0_79的版本进行分析. 注释比较详细. 若有不明白的地方可以指出, 我再进行细化.
public class HashMap<K,V>
extends AbstractMap<K,V>
implements Map<K,V>, Cloneable, Serializable
{
/**
* 默认容量为16
*/
static final int DEFAULT_INITIAL_CAPACITY = 1 << 4; // aka 16
/**
* 最大容量为2^30. 超过最大容量则, 自动转换为2^30
*/
static final int MAXIMUM_CAPACITY = 1 << 30;
/**
* 默认负载因子为0.75
*/
static final float DEFAULT_LOAD_FACTOR = 0.75f;
/**
* 空的Entry数组, 初始化使用
*/
static final Entry<?,?>[] EMPTY_TABLE = {};
/**
* Entry数组, 用于存放HashMap中的数据, 其大小必须为2的幂
* HashMap采用Hash表的方式存放数据, 若出现hash碰撞, 则采用单向链表的方式进行存储.
* 具体的实现方式在下面介绍
*/
transient Entry<K,V>[] table = (Entry<K,V>[]) EMPTY_TABLE;
/**
* Map的实际大小
*/
transient int size;
// 阀值, 当size超过该阀值时, 自动扩容量.
int threshold;
/**
* 负载因子
*/
final float loadFactor;
/**
* HashMap的修改次数. 仅用于采用iterator进行遍历时, 若发现modCount不同, 则直接报错. 即fail-fast模式.
*/
transient int modCount;
/**
* 默认构造函数.
* 默认容量为16
* 默认负载因子为0.75
* 默认的阀值是16*0.75=12
* 即当HashMap的size>12时, 则会自动扩充容量. 扩充后的容量=当前容量*2
* 在JDK1.7中HashMap中table在第一次put数据时才会被初始化, 具体初始化过程后面进行详细介绍
*/
public HashMap() {
this(DEFAULT_INITIAL_CAPACITY, DEFAULT_LOAD_FACTOR);
}
/**
* 带有初始容量及负载因子的构造器
*/
public HashMap(int initialCapacity, float loadFactor) {
if (initialCapacity < 0)
throw new IllegalArgumentException("Illegal initial capacity: " +
initialCapacity);
if (initialCapacity > MAXIMUM_CAPACITY)
initialCapacity = MAXIMUM_CAPACITY;
if (loadFactor <= 0 || Float.isNaN(loadFactor))
throw new IllegalArgumentException("Illegal load factor: " +
loadFactor);
this.loadFactor = loadFactor;
threshold = initialCapacity;
init();
}
/**
* 在HashMap子类中, 可以通过该方法进行一些初始化或扩展. 熟称Hook(钩子).
* 因为是包访问权限, 我们是用不到了. 有兴趣的可以看下LinkedHashMap中的实现.
*/
void init() {
}
/**
* 带有初始容量的构造器
*/
public HashMap(int initialCapacity) {
this(initialCapacity, DEFAULT_LOAD_FACTOR);
}
/**
* 我们来先看下put方法. 方法中涉及的其他方法将按照调用顺序逐个进行说明.
*/
public V put(K key, V value) {
//在put时进行初始化
//因为HashMap是非线程安全的, 所以如果在多线程中使用可能会导致数据被初始化多次.
//最终导致数据丢失.
if (table == EMPTY_TABLE) {
inflateTable(threshold);
}
//key==null时, 把该值put到table[0]中
//在HashMap中仅存在一个key=null的数据
if (key == null)
return putForNullKey(value);
//rehash, 重新计算key的hash值
int hash = hash(key);
//找到hash在table中的位置(索引)
int i = indexFor(hash, table.length);
//因为Hash表中的数据是采用单向链表的方式存储的, 所以这里通过索引取出该单向链表,
//然后逐个比对.
for (Entry<K,V> e = table[i]; e != null; e = e.next) {
Object k;
//值已经存在, 则替换value
//判断方式为:
// 1) 先判断hash值是否相同. 注: hash值相同key不一定相同
// 2) 再判断key是否相等
if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {
V oldValue = e.value;
e.value = value;
//空方法, 只在put时调用.
e.recordAccess(this);
return oldValue;
}
}
//modCount++, 记录数据修改次数. 方便做fail-fast
modCount++;
//若不存在该实体, 则创建新的Entry
addEntry(hash, key, value, i);
return null;
}
/**
* 往table中put key==null的值.
* 一个HashMap中只存在一个key==null的值, 且存放在table[0]中
*/
private V putForNullKey(V value) {
for (Entry<K,V> e = table[0]; e != null; e = e.next) {
//key已经存在, 则替换.
if (e.key == null) {
V oldValue = e.value;
e.value = value;
e.recordAccess(this);
return oldValue;
}
}
//创建新的Entry
modCount++;
addEntry(0, null, value, 0);
return null;
}
/**
* 初始化table
*/
private void inflateTable(int toSize) {
// 找到大于或等于toSize的2的幂, 具体查找方法看下方法roundUpToPowerOf2.
//有时候在面试时会被问到, 如果已知有18条数据, 那么在初始化HashMap时长度给定多少合适?
//如果面试官只关心长度, 那么你回答长度在17-32之间都可以. 可能他更想要的答案时32吧.
int capacity = roundUpToPowerOf2(toSize);
//而在JDK6中是通过不停的左移得到capacity的. 所以在JDK7中对此做了优化.
//int capacity = 1;
//while (capacity < initialCapacity)
// capacity <<= 1;
//初始化threshold
threshold = (int) Math.min(capacity * loadFactor, MAXIMUM_CAPACITY + 1);
//初始化table
table = new Entry[capacity];
//对String的特殊处理, 将放在最后进行介绍
//因为这一块是Jdk7中的尝试性方法, 在Jdk8中已经去掉了, 所以将不进行详细说明
initHashSeedAsNeeded(capacity);
}
/**
* 返回大于number的2的幂.
* if number>=2^30 return 2^30
* if number=1 return 1 即2^0
* else return 最接近number的2^x
*/
private static int roundUpToPowerOf2(int number) {
// assert number >= 0 : "number must be non-negative";
return number >= MAXIMUM_CAPACITY
? MAXIMUM_CAPACITY
: (number > 1)
//这里是避免number正好是2的幂. 所以采用number-1再左移一位的方式
? Integer.highestOneBit((number - 1) << 1)
: 1;
}
/**
* 此方法为Integer中的方法, 加进来只是为了方便说明.
* 该方法的返回结果为: 取输入值的最高位的1, 后面全部补0
*/
// public static int highestOneBit(int i) {
// // 这里以8为例. 8的二进制: 0000 1000
// i |= (i >> 1); //0000 1000 | 0000 0100 = 0000 1100
// i |= (i >> 2); //0000 1100 | 0000 0011 = 0000 1111
// i |= (i >> 4); //0000 1111 | 0000 1111 = 0000 1111
// i |= (i >> 8); //0000 1111 | 0000 1111 = 0000 1111
// i |= (i >> 16); //0000 1111 | 0000 1111 = 0000 1111
// //可以看出上面这些 右移 异或 等操作其实就是把最高位右移31位
// //最后的结果就是经过处理变成从最高位的1开始, 之后全部为1
// return i - (i >>> 1); //0000 1111 - 0000 0111 = 15 - 7 = 8
// }
/**
* 对key进行rehash, 让hash值更为散列, 尽量避免hash碰撞.
*/
final int hash(Object k) {
//这一块主要时为String类型进行特殊的hash处理,
//新的哈希算法可能会严重影响高并发、多线程代码. 所以在Jdk8中已经弃用.
//有兴趣的可以参考: http://www.importnew.com/7656.html
int h = hashSeed;
if (0 != h && k instanceof String) {
return sun.misc.Hashing.stringHash32((String) k);
}
h ^= k.hashCode();
// 主要是为了让高位低位都参与计算, 让hash值更散列.
// 在此不做详细介绍. 想了解的可以参照: http://www.iteye.com/topic/709945
h ^= (h >>> 20) ^ (h >>> 12);
return h ^ (h >>> 7) ^ (h >>> 4);
}
/**
* Returns index for hash code h.
* 计算hash在table中的位置.
* 通过该方法可以看出为什么要求table的length必须等于2的幂
* 1111 1111 & 0000 0010 = 0000 0010.
* 说白了就是把hash值与length-1取余
*/
static int indexFor(int h, int length) {
// assert Integer.bitCount(length) == 1 : "length must be a non-zero power of 2";
return h & (length-1);
}
/**
* 添加Entry, 当size>=threshold, 并且bucketIndex有值时进行resize.
*/
void addEntry(int hash, K key, V value, int bucketIndex) {
//当size>=threshold(阀值), 并且要加入的位置有值时进行容量扩充
//比如: new HashMap(), 默认的threshold=16*0.75=12
//也就是说当put第12个数据, 并且该位置上有值时进行resize
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);
}
/**
* 创建Entry, 并把Entry放到单向链表尾部
*/
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++;
}
/**
* 扩充table的大小. 并把原有数据转移到新的table中
*/
void resize(int newCapacity) {
Entry[] oldTable = table;
int oldCapacity = oldTable.length;
if (oldCapacity == MAXIMUM_CAPACITY) {
threshold = Integer.MAX_VALUE;
return;
}
Entry[] newTable = new Entry[newCapacity];
//把oldTable中的数据转移到newTable中
transfer(newTable, initHashSeedAsNeeded(newCapacity));
table = newTable;
//重新设置threshold
threshold = (int)Math.min(newCapacity * loadFactor, MAXIMUM_CAPACITY + 1);
}
/**
* 从oldTable中把数据转移到newTable中
* rehash: 默认为true, 通过该方法获取initHashSeedAsNeeded(newCapacity), 该方法是配合测试String的新的hash策略使用.
*/
void transfer(Entry[] newTable, boolean rehash) {
int newCapacity = newTable.length;
//遍历table中的每个Entry
for (Entry<K,V> e : table) {
while(null != e) {
//取出e.next, 方便后面做数据交换
Entry<K,V> next = e.next;
if (rehash) { //是否需要重新hash
e.hash = null == e.key ? 0 : hash(e.key);
}
//重新计算Entry在table中的位置
int i = indexFor(e.hash, newCapacity);
//进行数据交换.
//1. 把newTable[i]对应的Entry赋值给e.next. 即把e拼接到newTable[i]对应的链表中
e.next = newTable[i];
//2. 把e赋值给newTable[i]. 即: 把拼接后的newTable[i]放回到newTable中.
newTable[i] = e;
//3. 把next赋值给e, 继续往下遍历oldTable中的数据
e = next;
}
}
}
/**
* putAll与put差不多. 在此不做赘述. 可以参考put的说明
*/
public void putAll(Map<? extends K, ? extends V> m) {
int numKeysToBeAdded = m.size();
if (numKeysToBeAdded == 0)
return;
if (table == EMPTY_TABLE) {
inflateTable((int) Math.max(numKeysToBeAdded * loadFactor, threshold));
}
if (numKeysToBeAdded > threshold) {
int targetCapacity = (int)(numKeysToBeAdded / loadFactor + 1);
if (targetCapacity > MAXIMUM_CAPACITY)
targetCapacity = MAXIMUM_CAPACITY;
int newCapacity = table.length;
while (newCapacity < targetCapacity)
newCapacity <<= 1;
if (newCapacity > table.length)
resize(newCapacity);
}
for (Map.Entry<? extends K, ? extends V> e : m.entrySet())
put(e.getKey(), e.getValue());
}
/**
* 这个构造方法会在初始化时对table进行初始化. 初始化过程不在赘述
*/
public HashMap(Map<? extends K, ? extends V> m) {
this(Math.max((int) (m.size() / DEFAULT_LOAD_FACTOR) + 1,
DEFAULT_INITIAL_CAPACITY), DEFAULT_LOAD_FACTOR);
inflateTable(threshold);
putAllForCreate(m);
}
/**
* 通过key取值
*/
public V get(Object key) {
if (key == null)
return getForNullKey();
Entry<K,V> entry = getEntry(key);
return null == entry ? null : entry.getValue();
}
/**
* 从table[0]的Entry中取key=null的数据.
* 有时我们会通过map.get(key) == null来判断map中是否存在指定的数据,
* 一般情况下是不会有问题的. 但是如果正好key=null, value=null.
* 此时通过get(key)就无法区分map中是否真正存在这条数据了.
* 因为get(key)=null是有多种情况的:
* 1. value不存在
* 2. map为空
* 3. key不存在
* 所以判断数据是否存在还是用containsKey比较靠谱.
*/
private V getForNullKey() {
if (size == 0) {
return null;
}
//null的key默认放在table[0]中
for (Entry<K,V> e = table[0]; e != null; e = e.next) {
if (e.key == null)
return e.value;
}
return null;
}
/**
* 获取指定key对应的Entry
*/
final Entry<K,V> getEntry(Object key) {
if (size == 0) {
return null;
}
//null的hash默认为0.
int hash = (key == null) ? 0 : hash(key);
//循环table[indexFor(hash, table.length)]
//通过e.hash == hash && (key==e.key || key.equals(e.key)), 找到相应的entry
for (Entry<K,V> e = table[indexFor(hash, table.length)];
e != null;
e = e.next) {
Object k;
if (e.hash == hash &&
((k = e.key) == key || (key != null && key.equals(k))))
return e;
}
return null;
}
/**
* This method is used instead of put by constructors and
* pseudoconstructors (clone, readObject). It does not resize the table,
* check for comodification, etc. It calls createEntry rather than
* addEntry.
*
* 目前该方法仅在构造器中使用. 该方法不会resize table.
*/
private void putForCreate(K key, V value) {
int hash = null == key ? 0 : hash(key);
int i = indexFor(hash, table.length);
/**
* Look for preexisting entry for key. This will never happen for
* clone or deserialize. It will only happen for construction if the
* input Map is a sorted map whose ordering is inconsistent w/ equals.
*/
for (Entry<K,V> e = table[i]; e != null; e = e.next) {
Object k;
if (e.hash == hash &&
((k = e.key) == key || (key != null && key.equals(k)))) {
e.value = value;
return;
}
}
createEntry(hash, key, value, i);
}
//仅在构造器中使用.
private void putAllForCreate(Map<? extends K, ? extends V> m) {
for (Map.Entry<? extends K, ? extends V> e : m.entrySet())
putForCreate(e.getKey(), e.getValue());
}
/**
* 通过key移除数据
*/
public V remove(Object key) {
Entry<K,V> e = removeEntryForKey(key);
return (e == null ? null : e.value);
}
/**
* 通过key移除数据
*/
final Entry<K,V> removeEntryForKey(Object key) {
if (size == 0) {
return null;
}
int hash = (key == null) ? 0 : hash(key);
//取key在table中的位置
int i = indexFor(hash, table.length);
//取出数据, 方便后面进行操作
Entry<K,V> prev = table[i];
Entry<K,V> e = prev;
while (e != null) {
//先取出e.next
Entry<K,V> next = e.next;
Object k;
if (e.hash == hash &&
((k = e.key) == key || (key != null && key.equals(k)))) {
//设置modCount
modCount++;
size--;
//如果删除的元素在table[i]的第一个位置. 在需要把table[i]指给next;
//如果删除的元素在table[i]的其他位置. 则把table[i].next=next;
if (prev == e)
table[i] = next;
else
prev.next = next;
//Entry中的Hook方法. 方面子类进行扩展
e.recordRemoval(this);
return e;
}
//没找到, 则继续遍历
prev = e;
e = next;
}
return e;
}
/**
* 通过Entry移除数据, 根据entry.equals方法进行判断
*/
final Entry<K,V> removeMapping(Object o) {
if (size == 0 || !(o instanceof Map.Entry))
return null;
Map.Entry<K,V> entry = (Map.Entry<K,V>) o;
Object key = entry.getKey();
int hash = (key == null) ? 0 : hash(key);
int i = indexFor(hash, table.length);
Entry<K,V> prev = table[i];
Entry<K,V> e = prev;
while (e != null) {
Entry<K,V> next = e.next;
if (e.hash == hash && e.equals(entry)) {
modCount++;
size--;
//如果删除的元素在table[i]的第一个位置. 在需要把table[i]指给next;
//如果删除的元素在table[i]的其他位置. 则把table[i].next=next;
if (prev == e)
table[i] = next;
else
prev.next = next;
e.recordRemoval(this);
return e;
}
prev = e;
e = next;
}
return e;
}
/**
* 返回map的实际长度
*/
public int size() {
return size;
}
/**
* 判断map是否为空
*/
public boolean isEmpty() {
return size == 0;
}
/**
* 是否包含指定的key
*/
public boolean containsKey(Object key) {
return getEntry(key) != null;
}
/**
* 清空map
*/
public void clear() {
//需要注意table只会不断变大, 不会自动变小. 即使清空也只是清空里面的内容
//所以对于一个比较大的map对象, 清空后最好把该对象设置为null. 方便JVM回收.
modCount++;
Arrays.fill(table, null);
size = 0;
}
/**
* 判断map中是否包含指定的value.
* 当找到一个相等的value即返回true.
*/
public boolean containsValue(Object value) {
//containsValue是遍历全部数据, 效率不高
if (value == null)
return containsNullValue();
Entry[] tab = table;
for (int i = 0; i < tab.length ; i++)
for (Entry e = tab[i] ; e != null ; e = e.next)
if (value.equals(e.value))
return true;
return false;
}
/**
* 是否存在value=null的数据
* 当找到一个value==null的数据即返回true.
*/
private boolean containsNullValue() {
Entry[] tab = table;
for (int i = 0; i < tab.length ; i++)
for (Entry e = tab[i] ; e != null ; e = e.next)
if (e.value == null)
return true;
return false;
}
/**
* Returns a shallow copy of this <tt>HashMap</tt> instance: the keys and
* values themselves are not cloned.
*
* @return a shallow copy of this map
*/
public Object clone() {
HashMap<K,V> result = null;
try {
result = (HashMap<K,V>)super.clone();
} catch (CloneNotSupportedException e) {
// assert false;
}
if (result.table != EMPTY_TABLE) {
result.inflateTable(Math.min(
(int) Math.min(
size * Math.min(1 / loadFactor, 4.0f),
// we have limits...
HashMap.MAXIMUM_CAPACITY),
table.length));
}
result.entrySet = null;
result.modCount = 0;
result.size = 0;
result.init();
result.putAllForCreate(this);
return result;
}
//单向链表的数据结构
static class Entry<K,V> implements Map.Entry<K,V> {
final K key;
V value;
Entry<K,V> next;
int hash; //key的hash值
/**
* Creates new entry.
*/
Entry(int h, K k, V v, Entry<K,V> n) {
value = v;
next = n;
key = k;
hash = h;
}
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();
//两个Entry的key相等, 并且value也相等
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 Objects.hashCode(getKey()) ^ Objects.hashCode(getValue());
}
public final String toString() {
return getKey() + "=" + getValue();
}
/**
* put时调用
*/
void recordAccess(HashMap<K,V> m) {
}
/**
* remove时调用
*/
void recordRemoval(HashMap<K,V> m) {
}
}
private abstract class HashIterator<E> implements Iterator<E> {
Entry<K,V> next; // next entry to return
int expectedModCount; // For fast-fail
int index; // current slot
Entry<K,V> current; // current entry
HashIterator() {
//在创建iterator时把map中的modCount赋值给expectedModCount
//当遍历过程中发现expectedModCount != modCount时直接报错
//出现这种情况, 则说明有其他线程操作了(put/remove)该map
//所以在遍历hashMap时建议使用iterator, 避免出现数据处理异常
expectedModCount = modCount;
if (size > 0) { // advance to first entry
Entry[] t = table;
while (index < t.length && (next = t[index++]) == null)
;
}
}
public final boolean hasNext() {
return next != null;
}
final Entry<K,V> nextEntry() {
if (modCount != expectedModCount) //fail-fast
throw new ConcurrentModificationException();
Entry<K,V> e = next;
if (e == null)
throw new NoSuchElementException();
if ((next = e.next) == null) {
Entry[] t = table;
while (index < t.length && (next = t[index++]) == null)
;
}
current = e;
return e;
}
public void remove() {
if (current == null)
throw new IllegalStateException();
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
Object k = current.key;
current = null;
HashMap.this.removeEntryForKey(k);
expectedModCount = modCount;
}
}
private final class ValueIterator extends HashIterator<V> {
public V next() {
return nextEntry().value;
}
}
private final class KeyIterator extends HashIterator<K> {
public K next() {
return nextEntry().getKey();
}
}
private final class EntryIterator extends HashIterator<Map.Entry<K,V>> {
public Map.Entry<K,V> next() {
return nextEntry();
}
}
// Subclass overrides these to alter behavior of views' iterator() method
Iterator<K> newKeyIterator() {
return new KeyIterator();
}
Iterator<V> newValueIterator() {
return new ValueIterator();
}
Iterator<Map.Entry<K,V>> newEntryIterator() {
return new EntryIterator();
}
// Views
private transient Set<Map.Entry<K,V>> entrySet = null;
/**
* 返回所有的key
*/
public Set<K> keySet() {
Set<K> ks = keySet;
return (ks != null ? ks : (keySet = new KeySet()));
}
private final class KeySet extends AbstractSet<K> {
public Iterator<K> iterator() {
return newKeyIterator();
}
public int size() {
return size;
}
public boolean contains(Object o) {
return containsKey(o);
}
public boolean remove(Object o) {
return HashMap.this.removeEntryForKey(o) != null;
}
public void clear() {
HashMap.this.clear();
}
}
/**
* 返回所有的values
*/
public Collection<V> values() {
Collection<V> vs = values;
return (vs != null ? vs : (values = new Values()));
}
private final class Values extends AbstractCollection<V> {
public Iterator<V> iterator() {
return newValueIterator();
}
public int size() {
return size;
}
public boolean contains(Object o) {
return containsValue(o);
}
public void clear() {
HashMap.this.clear();
}
}
/**
* 返回所有的Entry
*/
public Set<Map.Entry<K,V>> entrySet() {
return entrySet0();
}
private Set<Map.Entry<K,V>> entrySet0() {
Set<Map.Entry<K,V>> es = entrySet;
return es != null ? es : (entrySet = new EntrySet());
}
private final class EntrySet extends AbstractSet<Map.Entry<K,V>> {
public Iterator<Map.Entry<K,V>> iterator() {
return newEntryIterator();
}
public boolean contains(Object o) {
if (!(o instanceof Map.Entry))
return false;
Map.Entry<K,V> e = (Map.Entry<K,V>) o;
Entry<K,V> candidate = getEntry(e.getKey());
return candidate != null && candidate.equals(e);
}
public boolean remove(Object o) {
return removeMapping(o) != null;
}
public int size() {
return size;
}
public void clear() {
HashMap.this.clear();
}
}
/**
* 下面的方法不再做重复复述. 有兴趣的可以参考: http://www.importnew.com/7656.html
*/
static final int ALTERNATIVE_HASHING_THRESHOLD_DEFAULT = Integer.MAX_VALUE;
/**
* holds values which can't be initialized until after VM is booted.
*/
private static class Holder {
/**
* Table capacity above which to switch to use alternative hashing.
*/
static final int ALTERNATIVE_HASHING_THRESHOLD;
static {
String altThreshold = java.security.AccessController.doPrivileged(
new sun.security.action.GetPropertyAction(
"jdk.map.althashing.threshold"));
int threshold;
try {
threshold = (null != altThreshold)
? Integer.parseInt(altThreshold)
: ALTERNATIVE_HASHING_THRESHOLD_DEFAULT;
// disable alternative hashing if -1
if (threshold == -1) {
threshold = Integer.MAX_VALUE;
}
if (threshold < 0) {
throw new IllegalArgumentException("value must be positive integer.");
}
} catch(IllegalArgumentException failed) {
throw new Error("Illegal value for 'jdk.map.althashing.threshold'", failed);
}
ALTERNATIVE_HASHING_THRESHOLD = threshold;
}
}
/**
* A randomizing value associated with this instance that is applied to
* hash code of keys to make hash collisions harder to find. If 0 then
* alternative hashing is disabled.
*/
transient int hashSeed = 0;
/**
* Initialize the hashing mask value. We defer initialization until we
* really need it.
*/
final boolean initHashSeedAsNeeded(int capacity) {
boolean currentAltHashing = hashSeed != 0;
boolean useAltHashing = sun.misc.VM.isBooted() &&
(capacity >= Holder.ALTERNATIVE_HASHING_THRESHOLD);
boolean switching = currentAltHashing ^ useAltHashing;
if (switching) {
hashSeed = useAltHashing
? sun.misc.Hashing.randomHashSeed(this)
: 0;
}
return switching;
}
}
JDK7 HashMap源码分析的更多相关文章
- Java HashMap源码分析(含散列表、红黑树、扰动函数等重点问题分析)
写在最前面 这个项目是从20年末就立好的 flag,经过几年的学习,回过头再去看很多知识点又有新的理解.所以趁着找实习的准备,结合以前的学习储备,创建一个主要针对应届生和初学者的 Java 开源知识项 ...
- 【JAVA集合】HashMap源码分析(转载)
原文出处:http://www.cnblogs.com/chenpi/p/5280304.html 以下内容基于jdk1.7.0_79源码: 什么是HashMap 基于哈希表的一个Map接口实现,存储 ...
- Java中HashMap源码分析
一.HashMap概述 HashMap基于哈希表的Map接口的实现.此实现提供所有可选的映射操作,并允许使用null值和null键.(除了不同步和允许使用null之外,HashMap类与Hashtab ...
- JDK1.8 HashMap源码分析
一.HashMap概述 在JDK1.8之前,HashMap采用数组+链表实现,即使用链表处理冲突,同一hash值的节点都存储在一个链表里.但是当位于一个桶中的元素较多,即hash值相等的元素较多时 ...
- HashMap源码分析和应用实例的介绍
1.HashMap介绍 HashMap 是一个散列表,它存储的内容是键值对(key-value)映射.HashMap 继承于AbstractMap,实现了Map.Cloneable.java.io.S ...
- 【Java】HashMap源码分析——常用方法详解
上一篇介绍了HashMap的基本概念,这一篇着重介绍HasHMap中的一些常用方法:put()get()**resize()** 首先介绍resize()这个方法,在我看来这是HashMap中一个非常 ...
- 【Java】HashMap源码分析——基本概念
在JDK1.8后,对HashMap源码进行了更改,引入了红黑树.在这之前,HashMap实际上就是就是数组+链表的结构,由于HashMap是一张哈希表,其会产生哈希冲突,为了解决哈希冲突,HashMa ...
- Java BAT大型公司面试必考技能视频-1.HashMap源码分析与实现
视频通过以下四个方面介绍了HASHMAP的内容 一. 什么是HashMap Hash散列将一个任意的长度通过某种算法(Hash函数算法)转换成一个固定的值. MAP:地图 x,y 存储 总结:通过HA ...
- Java源码解析——集合框架(五)——HashMap源码分析
HashMap源码分析 HashMap的底层实现是面试中问到最多的,其原理也更加复杂,涉及的知识也越多,在项目中的使用也最多.因此清晰分析出其底层源码对于深刻理解其实现有重要的意义,jdk1.8之后其 ...
随机推荐
- 移动应用产品开发-android开发 新闻模块开发 百度Frontia组件应用之分享
这两天主要做了新闻模块的开发,做了新闻列表,新闻详情,数据结构解析,以及百度 Frontia 组件的研究. 新闻模块用的是开源中国的android开源代码里的代码,主要是模仿它的源码架构,首先打开是资 ...
- Hibernate 注解 没有加@Column一样会在数据库创建这些字段
Hibernate 注解 没有加@Column一样会在数据库创建这些字段 如下一个注解类: package com.hyy.hibernate.one_to_many.domain; import j ...
- http://jinnianshilongnian.iteye.com/blog/1996071
http://jinnianshilongnian.iteye.com/blog/1996071 http://my.oschina.net/jkcui/blog/388400 http://tian ...
- VS2012中使用纯C实现COM的小问题
用VS2012新建C++工程都预定义了宏__cplusplus,所以引用到的都是C++的定义.但是要用C实现的话,一般都是也就不是C++的了.比如以下代码: #undef INTERFACE #def ...
- C/C++ ceil和floor函数
ceil 是“天花板" floor 是 “地板” 一个靠上取值,另一个靠下取值,如同天花板,地板. double ceil ( double x ); float ceil ( float ...
- IP 碎片重组
IP 碎片重组 内核中的IP重组函数. struct sk_buff * ip_defrag(struct sk_buff * skb, u32 user) { ...... //如果内核范围超出限制 ...
- bzoj3172
这里学习AC自动机其实对KMP和trie掌握好了之后很容易扩展成AC自动机的这里运用了一个性质由失配指针反向可以建成一棵fail树x串在y串中的出现的次数即为在fail树上以x结尾节点为根的子树中有多 ...
- 【转】Android开发之旅:环境搭建及HelloWorld
原文网址: http://www.cnblogs.com/skynet/archive/2010/04/12/1709892.html 引言 本系列适合0基础的人员,因为我就是从0开始的,此系列记录我 ...
- 字符串(AC自动机):HDU 5129 Yong Zheng's Death
Yong Zheng's Death Time Limit: 20000/10000 MS (Java/Others) Memory Limit: 512000/512000 K (Java/O ...
- No setter found for property 'userDAO' in class 'com.ssh.service.impl.User1Service'
造成此问题的原因是: 在applicationContext.xml中引用 <bean id="userService" class="com.ssh.servic ...