一、HashTable
数据+链表
put方法:
1.Hasbtable并不允许值和键为空(null),若为空,会抛空指针。
2.HashMap计算索引的方式是h&(length-1),而Hashtable用的是模运算,效率上是低于HashMap的。
3.特别需要注意的是这个方法包括下面要讲的若干方法都加了synchronized关键字,也就意味着这个Hashtable是个线程安全的类,这也是它和HashMap最大的不同点.
4、HashTable默认容量是11 HashMap默认为16
public synchronized V put(K key, V value) {//向哈希表中添加键值对
// Make sure the value is not null
if (value == null) {//确保值不能为空
throw new NullPointerException();
}
// Makes sure the key is not already in the hashtable.
Entry tab[] = table;
int hash = hash(key);//根据键生成hash值---->若key为null,此方法会抛异常
int index = (hash & 0x7FFFFFFF) % tab.length;//通过hash值找到其存储位置
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;
}
}
modCount++;
if (count >= threshold) {//当前容量超过阈值。需要扩容
// Rehash the table if the threshold is exceeded
rehash();//重新构建桶数组,并对数组中所有键值对重哈希,耗时!
tab = table;
hash = hash(key);
index = (hash & 0x7FFFFFFF) % tab.length;//这里是取摸运算
}
// Creates the new entry.
Entry<K,V> e = tab[index];
//将新结点插到链表首部
tab[index] = new Entry<>(hash, key, value, e);//生成一个新结点
count++;
return null;
}
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;//初始容量最小值为1
this.loadFactor = loadFactor;
table = new Entry[initialCapacity];//创建桶数组
threshold = (int)Math.min(initialCapacity * loadFactor, MAX_ARRAY_SIZE + 1);//初始化容量阈值
useAltHashing = sun.misc.VM.isBooted() &&
(initialCapacity >= Holder.ALTERNATIVE_HASHING_THRESHOLD);
}
/**
* Constructs a new, empty hashtable with the specified initial capacity
* and default load factor (0.75).
*/
public Hashtable(int initialCapacity) {
this(initialCapacity, 0.75f);//默认负载因子为0.75
}
public Hashtable() {
this(11, 0.75f);//默认容量为11,负载因子为0.75
}
/**
* Constructs a new hashtable with the same mappings as the given
* Map. The hashtable is created with an initial capacity sufficient to
* hold the mappings in the given Map and a default load factor (0.75).
*/
public Hashtable(Map<? extends K, ? extends V> t) {
this(Math.max(2*t.size(), 11), 0.75f);
putAll(t);
}
二、LinkedHashMap
双向链表+数组
HashMap 是无序的,HashMap 在 put 的时候是根据 key 的 hashcode 进行 hash 然后放入对应的地方。所以在按照一定顺序 put 进 HashMap 中,然后遍历出 HashMap 的顺序跟 put 的顺序不同(除非在 put 的时候 key 已经按照 hashcode 排序号了,这种几率非常小)
JAVA 在 JDK1.4 以后提供了 LinkedHashMap 来帮助我们实现了有序的 HashMap!
LinkedHashMap 是 HashMap 的一个子类,它保留插入的顺序,如果需要输出的顺序和输入时的相同,那么就选用 LinkedHashMap。
LinkedHashMap 是 Map 接口的哈希表和链接列表实现,具有可预知的迭代顺序。此实现提供所有可选的映射操作,并允许使用 null 值和 null 键。此类不保证映射的顺序,特别是它不保证该顺序恒久不变。
LinkedHashMap 实现与 HashMap 的不同之处在于,LinkedHashMap 维护着一个运行于所有条目的双重链接列表。此链接列表定义了迭代顺序,该迭代顺序可以是插入顺序或者是访问顺序。
注意,此实现不是同步的。如果多个线程同时访问链接的哈希映射,而其中至少一个线程从结构上修改了该映射,则它必须保持外部同步。
根据链表中元素的顺序可以分为:按插入顺序的链表,和按访问顺序(调用 get 方法)的链表。默认是按插入顺序排序,如果指定按访问顺序排序,那么调用get方法后,会将这次访问的元素移至链表尾部,不断访问可以形成按访问顺序排序的链表。
三、TreeMap
红黑树 key-value排序(用key),要求key必须是同一个类的对象,按照key进行排序:
自然排序,定制排序。
四、Properties
常用来处理配置文件,key和value都是string类型