HashMap 和 HashSet 是 Java Collection Framework 的两个重要成员,其中 HashMap 是 Map 接口的常用实现类,HashSet 是 Set 接口的常用实现类。
HashMap
HashMap具有以下特点:
基于数组+链表实现,数组里的元素是一个单向链表。
键不可以重复,值可以重复,键、值都可以为null
非线程安全
实现了Map, Cloneable, Serializable接口
成员变量
static final int DEFAULT_INITIAL_CAPACITY = 16;// 默认初始容量为16,必须为2的幂
static final int MAXIMUM_CAPACITY = 1 << 30;// 最大容量为2的30次方
static final float DEFAULT_LOAD_FACTOR = 0.75f;// 默认加载因子0.75
transient Entry<K,V>[] table;// Entry数组,哈希表,长度必须为2的幂
transient int size;// 已存元素的个数
int threshold;// 下次扩容的临界值,值为初始容量*加载因子;size>=threshold就会扩容
final float loadFactor;// 加载因子,手动设置的加载因子
transient int modCount;//改变次数
static final int ALTERNATIVE_HASHING_THRESHOLD_DEFAULT = Integer.MAX_VALUE;//默认阀值
构造方法
//传入容量与加载银子
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();
}
//传入容量
public HashMap(int initialCapacity) {
this(initialCapacity, DEFAULT_LOAD_FACTOR);
}
//无参构造
public HashMap() {
this(DEFAULT_INITIAL_CAPACITY, DEFAULT_LOAD_FACTOR);
}
//传入一个map
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);
}
size
返回当前长度
public int size() {
return size;
}
isEmpty
判断当前是否为空
public boolean isEmpty() {
return size == 0;
}
hash
计算hash
final int hash(Object k) {
int h = hashSeed;
if (0 != h && k instanceof String) {
return sun.misc.Hashing.stringHash32((String) k);
}
h ^= k.hashCode();
h ^= (h >>> 20) ^ (h >>> 12);
return h ^ (h >>> 7) ^ (h >>> 4);
}
put
public V put(K key, V value) {
if (key == null)
return putForNullKey(value);
/*如果key为null则调用 putForNullKey(value) 函数 这个函数先在table[0]这条链上找有没有key 为null的元素如果有就覆盖,如果没有就新建一个new一个key为null,value=value hash=0,的Entry放在table[0]。
*/
int hash = hash(key);
//获得key的hash值
int i = indexFor(hash, table.length);
//由hash值确定放在table表中的那一条链上。类似于取模后放在数组中的哪个位置。
for (Entry<K,V> e = table[i]; e != null; e = e.next) {
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;
//如果链上原来有一个hash值相同,且key相同的则用新的value值进行覆盖。
}
}
//否则利用hash,key,value,new一个Entry对象插入到链表中。
modCount++;
addEntry(hash, key, value, i);
return null;
}
putForNullKey
将key为null的键值对插入0好位置
private V putForNullKey(V value) {
for (Entry<K,V> e = table[0]; e != null; e = e.next) {
if (e.key == null) {
V oldValue = e.value;
e.value = value;
e.recordAccess(this);
return oldValue;
}
}
modCount++;
addEntry(0, null, value, 0);
return null;
}
indexFor
这里用&代替了%,提高了效率
返回某个对象的下标
static int indexFor(int h, int length) {
return h & (length-1);
}
get
通过key查询value
public V get(Object key) {
if (key == null)
return getForNullKey();
//获取Entry
Entry<K,V> entry = getEntry(key);
//返回值
return null == entry ? null : entry.getValue();
}
getForNullKey
获取key为null的值
private V getForNullKey() {
if (size == 0) {
return null;
}
for (Entry<K,V> e = table[0]; e != null; e = e.next) {
if (e.key == null)
return e.value;
}
return null;
}
containsKey
是否存在某个key
public boolean containsKey(Object key) {
return getEntry(key) != null;
}
containsValue
是否存在某个值
public boolean containsValue(Object value) {
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;
}
resize
扩容
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];
//将原数组复制,获取到新的hash掩码然后重新哈希
transfer(newTable, initHashSeedAsNeeded(newCapacity));
//切换table
table = newTable;
//更改阀值
threshold = (int)Math.min(newCapacity * loadFactor, MAXIMUM_CAPACITY + 1);
}
remove
通过key删除value
public V remove(Object key) {
Entry<K,V> e = removeEntryForKey(key);
return (e == null ? null : e.value);
}
clear
清空
public void clear() {
modCount++;
Arrays.fill(table, null);
size = 0;
}
hashtable
特点:
1,基于数组+链表实现,是一个双向链表
2,线程安全
3,实现了Map, Cloneable, java.io.Serializable接口
成员变量
private transient Entry<K,V>[] table;
private transient Entry[] table; // 由Entry对象组成的链表数组
private transient int count; // Hashtable中Entry对象的个数
private int threshold; // Hashtable进行扩容的阈值
private float loadFactor; // 加载因子,默认为0.75
private transient int modCount = 0; // 记录Hashtable修改的次数
private static final long serialVersionUID = 1421746759512286392L;
static final int ALTERNATIVE_HASHING_THRESHOLD_DEFAULT = Integer.MAX_VALUE;
构造函数
//指定容量大小和加载因子的构造方法
public Hashtable(int initialCapacity, float loadFactor) {
if (initialCapacity < 0)
throw new IllegalArgumentException("Illegal Capacity: "+
initialCapacity);
if (loadFactor <= 0 || Float.isNaN(loadFactor))
throw new IllegalArgumentException("Illegal Load: "+loadFactor);
if (initialCapacity==0)
initialCapacity = 1;
this.loadFactor = loadFactor;
//创建hash数组
table = new Entry[initialCapacity];
threshold = (int)Math.min(initialCapacity * loadFactor, MAX_ARRAY_SIZE + 1);
useAltHashing = sun.misc.VM.isBooted() &&
(initialCapacity >= Holder.ALTERNATIVE_HASHING_THRESHOLD);
}
// 指定容量大小和默认加载因子(0.75)的构造方法
public Hashtable(int initialCapacity) {
this(initialCapacity, 0.75f);
}
// 指定默认初始容量(11)和默认加载因子(0.75)的构造方法
public Hashtable() {
this(11, 0.75f);
}
// 带有Map参数的构造函数
public Hashtable(Map<? extends K, ? extends V> t) {
this(Math.max(2*t.size(), 11), 0.75f);
//将map中的所有元素加入到Hashtable中
putAll(t);
}
size
返回元素数量
public synchronized int size() {
return count;
}
isEmpty
判断是否为空
public synchronized boolean isEmpty() {
return count == 0;
}
contains
判断Hashtable中是否包含值为value的元素,
public synchronized boolean contains(Object value) {
if (value == null) {//Object为null,则抛出空指针
throw new NullPointerException();
}
Entry tab[] = table;
for (int i = tab.length ; i-- > 0 ;) {
for (Entry<K,V> e = tab[i] ; e != null ; e = e.next) {
if (e.value.equals(value)) {
return true;
}
}
}
return false;
}
containsValue
判断是否存在某个值
public boolean containsValue(Object value) {
return contains(value);
}
containsKey
判断是否存在某个key
public synchronized boolean containsKey(Object key) {
Entry tab[] = table;
int hash = hash(key);
int index = (hash & 0x7FFFFFFF) % tab.length;
for (Entry<K,V> e = tab[index] ; e != null ; e = e.next) {
if ((e.hash == hash) && e.key.equals(key)) {
return true;
}
}
return false;
}
get
通过key获取value
public synchronized V get(Object key) {
Entry tab[] = table;
int hash = hash(key);
int index = (hash & 0x7FFFFFFF) % tab.length;
for (Entry<K,V> e = tab[index] ; e != null ; e = e.next) {
if ((e.hash == hash) && e.key.equals(key)) {
return e.value;
}
}
return null;
}
rehash
进行扩容
protected void rehash() {
//旧数组大小oldCapacity
int oldCapacity = table.length;
Entry<K,V>[] oldMap = table;
// 新数组长度 = 旧数组长度*2 + 1
int newCapacity = (oldCapacity << 1) + 1;
if (newCapacity - MAX_ARRAY_SIZE > 0) {
if (oldCapacity == MAX_ARRAY_SIZE)
// Keep running with MAX_ARRAY_SIZE buckets
return;
newCapacity = MAX_ARRAY_SIZE;
}
//创建新数组
Entry<K,V>[] newMap = new Entry[newCapacity];
//修改次数+1
modCount++;
threshold = (int)Math.min(newCapacity * loadFactor, MAX_ARRAY_SIZE + 1);
boolean currentAltHashing = useAltHashing;
useAltHashing = sun.misc.VM.isBooted() &&
(newCapacity >= Holder.ALTERNATIVE_HASHING_THRESHOLD);
boolean rehash = currentAltHashing ^ useAltHashing;
table = newMap;
//将旧数组中的数据依次添加到新table数组中
for (int i = oldCapacity ; i-- > 0 ;) {
for (Entry<K,V> old = oldMap[i] ; old != null ; ) {
Entry<K,V> e = old;
old = old.next;
if (rehash) {
e.hash = hash(e.key);
}
int index = (e.hash & 0x7FFFFFFF) % newCapacity;
e.next = newMap[index];
newMap[index] = e;
}
}
}
put
添加键值对
public synchronized V put(K key, V value) {
//HashTable中不能插入value为null的元素
if (value == null) {
throw new NullPointerException();
}
// 若HashTable中已存在键为key的键值对,则用新的value替换旧的value
Entry tab[] = table;
int hash = hash(key);
int index = (hash & 0x7FFFFFFF) % tab.length;
for (Entry<K,V> e = tab[index] ; e != null ; e = e.next) {
if ((e.hash == hash) && e.key.equals(key)) {
V old = e.value;
e.value = value;
return old;
}
}
//更改修改次数+1
modCount++;
if (count >= threshold) {
// Rehash the table if the threshold is exceeded
rehash();
tab = table;
hash = hash(key);
index = (hash & 0x7FFFFFFF) % tab.length;
}
//将Hashtable中index位置的Entry(链表)保存到e中,将键值对插进entry链表中
Entry<K,V> e = tab[index];
tab[index] = new Entry<>(hash, key, value, e);
//元素数量+1
count++;
return null;
}
remove
通过key删除键值对
public synchronized V remove(Object key) {
Entry tab[] = table;
int hash = hash(key);
int index = (hash & 0x7FFFFFFF) % tab.length;
for (Entry<K,V> e = tab[index], prev = null ; e != null ; prev = e, e = e.next) {
if ((e.hash == hash) && e.key.equals(key)) {
modCount++;
if (prev != null) {
prev.next = e.next;
} else {
tab[index] = e.next;
}
count--;
V oldValue = e.value;
e.value = null;
return oldValue;
}
}
return null;
}
**clea**r
进行清空
public synchronized void clear() {
Entry tab[] = table;
modCount++;
for (int index = tab.length; --index >= 0; )
tab[index] = null;
count = 0;
}