先上一张Java集合的框架图,便于参考
以下所有特性仅代表自JAVA 1.8
Map
public interface Map<K,V> {
int size();
boolean containsKey(Object key);
V put(K key, V value);
V remove(Object key);
void clear();
.
.
.
}
HashMap
public class HashMap<K,V> extends AbstractMap<K,V>
implements Map<K,V>, Cloneable, Serializable{
/**
* The default initial capacity - MUST be a power of two.
*/
static final int DEFAULT_INITIAL_CAPACITY = 1 << 4; // aka 16
/**
* The load factor used when none specified in constructor.
*/
static final float DEFAULT_LOAD_FACTOR = 0.75f;
/**
* The table, initialized on first use, and resized as
* necessary. When allocated, length is always a power of two.
* (We also tolerate length zero in some operations to allow
* bootstrapping mechanics that are currently not needed.)
*/
transient Node<K,V>[] table;
static class Node<K,V> implements Map.Entry<K,V> {
final int hash;
final K key;
V value;
Node<K,V> next;
}
}
1.Hashmap默认初始化容量为16,负载因子默认0.75
2.使用 Node<K,V>[] table (数组) 和 Node<K,V>[](单向链表) 来存储数据
static class Node<K,V> implements Map.Entry<K,V> {
final int hash;
final K key;
V value;
Node<K,V> next;
}
3.HashMap将会自动扩容当内存容量大于 (Capacity * loadFactor)时
4.扩容后的新 Capacity 将会是旧的容量的两倍
5.使用Key计算出 hashcode, 再转化为在数组 (Node<K,V>[])table中的位置 所以 HashMap是无序的
6.HashMap没有使用同步机制,所以HashMap是线程不安全的
LinkedHashMap
public class LinkedHashMap<K,V>
extends HashMap<K,V>
implements Map<K,V>{
/**
* The head (eldest) of the doubly linked list.
*/
transient LinkedHashMap.Entry<K,V> head;
/**
* The tail (youngest) of the doubly linked list.
*/
transient LinkedHashMap.Entry<K,V> tail;
static class Entry<K,V> extends HashMap.Node<K,V> {
Entry<K,V> before, after;
}
}
1.默认初始化容量为16,负载因子默认0.75
2.使用 Entry[16] table 和 Entry<K,V>(双向链表)来存储数据
static class Entry<K,V> extends HashMap.Node<K,V> {
Entry<K,V> before, after;
}
3.LinkedHashMap将会自动扩容当内存容量超过(Capacity * loadFactor)
4.新容量Capacity将会是旧的容量的两倍
5.使用hashcode来计算数据在数组 (Entry[])table中的位置,但是使用双向链表结构来存储数据和记录顺序,所以LinkedHashMap是有序的。
6.LinkedHashMap没有使用同步机制,所以LinkedHashMap是线程不安全的
TreeMap TreeMap底层实现原理
public class TreeMap<K,V>
extends AbstractMap<K,V>
implements NavigableMap<K,V>, Cloneable, java.io.Serializable
{
private transient Entry<K,V> root;
static final class Entry<K,V> implements Map.Entry<K,V> {
K key;
V value;
Entry<K,V> left;
Entry<K,V> right;
Entry<K,V> parent;
boolean color = BLACK; //Using the Red-Black Tree
}
}
1.TreeMap是按照Key的自然顺序或者Comprator的顺序进行排序,因此TreeMap是有序的
2.无初始化大小,数据添加不需要扩容
3.使用红黑树数据结构存储数据
4.没有使用同步机制或锁,TreeMap是线程不安全的
HashTable
public class Hashtable<K,V>
extends Dictionary<K,V>
implements Map<K,V>, Cloneable, java.io.Serializable {
/**
* The hash table data.
*/
private transient Entry<?,?>[] table;
public Hashtable() {
this(11, 0.75f);
}
/**
* Hashtable bucket collision list entry
*/
private static class Entry<K,V> implements Map.Entry<K,V> {
final int hash;
final K key;
V value;
Entry<K,V> next;
}
@SuppressWarnings("unchecked")
public synchronized V get(Object key) {
Entry<?,?> tab[] = table;
int hash = key.hashCode();
int index = (hash & 0x7FFFFFFF) % tab.length;
for (Entry<?,?> e = tab[index] ; e != null ; e = e.next) {
if ((e.hash == hash) && e.key.equals(key)) {
return (V)e.value;
}
}
return null;
}
}
1.基本实现原理和HashMap一致,HashTable通过synchronized同步代码块和 CAS操作来实现线程安全,因此HashTable是线程安全的
2.默认初始大小11,加载因子0.75,每次扩容为 2n+1
ConcurrentHashMap
public class ConcurrentHashMap<K,V> extends AbstractMap<K,V>
implements ConcurrentMap<K,V>, Serializable {
private static final int DEFAULT_CAPACITY = 16;
private static final float LOAD_FACTOR = 0.75f;
transient volatile Node<K,V>[] table;
/**
* The next table to use; non-null only while resizing.
*/
private transient volatile Node<K,V>[] nextTable;
//jdk1.8中虽然不在使用分段锁,但是仍然有Segment这个类,但是没有实际作用
static class Segment<K,V> extends ReentrantLock implements Serializable {
private static final long serialVersionUID = 2249069246763182397L;
final float loadFactor;
Segment(float lf) { this.loadFactor = lf; }
}
static class Node<K,V> implements Map.Entry<K,V> {
final int hash;
final K key;
volatile V val;
volatile Node<K,V> next;
}
}
1.Node数组使用来存放树或者链表的头结点,当一个链表中的数量到达一个数目时,会使查询速率降低,所以到达一定阈值时,会将一个链表转换为一个红黑二叉树,提升查询的速率。
2.使用Synchroized关键字来同步代码块,因此ConcurrentHashMap是线程安全的
3.扩容为原来的两倍