????Java集合(一)集合框架使用综述 ????Java集合(二)ArrayList使用及源码分析 ????Java集合(三)LinkedList使用及源码分析 ????Java集合(四)Vector源码使用及源码分析 ????Java集合(五)Stack使用及源码分析 ????Java集合(六)HashMap使用及源码分析 ????Java集合(七)Hashtable使用及源码分析
一、Hashtable概述
??HashMap是jdk中最常用的哈希表实现,使用数组加链表的结构来组织数据,不过HashMap是线程不安全的。因此,Hashtable作为线程安全的Map实现诞生了。其继承关系:
public class Hashtable<K,V>
extends Dictionary<K,V>
implements Map<K,V>, Cloneable, java.io.Serializable
??HashMap和HashTabel用法几乎一样,底层实现也几乎一样,但是HashTable的方法添加了synchronized关键字以确保线程安全,但同时也导致效率较低。两者的区别:
- 1、 hashmap中key和value均可以为null,但是
hashtable中key和value均不能为null 。 - 2、 hashmap采用的是数组(桶位)+链表+红黑树结构实现,而hashtable中采用的是数组(桶位)+链表实现。
- 3、 hashmap中出现hash冲突时,如果链表节点数小于8时是将新元素加入到链表的末尾,而hashtable中出现hash冲突时采用的是将新元素加入到链表的开头。
- 4、 hashmap中数组容量的大小要求是2的n次方,如果初始化时不符合要求会进行调整,而hashtable中数组容量的大小可以为任意正整数。
- 5、 hashmap中的寻址方法采用的是位运算按位与,而hashtable中寻址方式采用的是求余数。
- 6、 hashmap不是线程安全的,而hashtable是线程安全的,hashtable中的get和put方法均采用了synchronized关键字进行了方法同步。
- 7、 hashmap中默认容量的大小是16,而hashtable中默认数组容量是11。
二、Hashtable使用
2.1 构造方法
1、构造一个新的,空的散列表,默认初始容量(11)和负载因子(0.75)。 ??public Hashtable() 2、构造一个新的,空的哈希表,具有指定的初始容量和默认负载因子(0.75)。 ??public Hashtable(int initialCapacity) 3、构造一个新的,空的哈希表,具有指定的初始容量和指定的负载因子。 ??public Hashtable(int initialCapacity, float loadFactor) 4、构造一个与给定地图相同的映射的新哈希表。 ??public Hashtable(Map<? extends K, ? extends V> t)
??使用示例:
Hashtable<String, String> hashtable = new Hashtable<>();
Hashtable<String, String> hashtable2 = new Hashtable<>(18);
Hashtable<String, String> hashtable3 = new Hashtable<>(18,0.5f);
HashMap<String, String> hashMap = new HashMap<>();
Hashtable<String, String> hashtable4 = new Hashtable<>(hashMap);
2.2 clear
清空Hashtable ??public synchronized void clear()
??使用示例:
Hashtable<String, String> hashtable = new Hashtable<>();
hashtable.clear();
2.3 clone
创建这个散列表的浅拷贝 ??public synchronized Object clone()
??使用示例:
Hashtable<String, String> hashtable = new Hashtable<>();
Hashtable<String, String> hashtable2 = (Hashtable<String, String>) hashtable.clone();
2.4 compute
如果在Hashtable的compute()中传递的重映射函数返回null作为返回值,则该映射将从Hashtable中删除(如果最初不存在,则保持不存在)。 ??public synchronized V computeIfAbsent(K key, Function<? super K, ? extends V> mappingFunction)
??使用示例:
Map<String, Integer> table = new Hashtable<>();
table.put("Pen", 10);
System.out.println("hashTable: " + table.toString());
table.compute("Pen", (key, val) -> val + 15);
System.out.println("new hashTable: " + table);
2.5 computeIfAbsent
如果指定的键尚未与某个值相关联(或映射到 null ),则尝试使用给定的映射函数计算其值,并将其输入到此映射中,除非 null 。 ??public synchronized V computeIfAbsent(K key, Function<? super K, ? extends V> mappingFunction)
??使用示例:
Map<String, Integer> table = new Hashtable<>();
table.put("Pen", 10);
table.put("Book", 500);
table.put("Clothes", 400);
table.put("Mobile", 5000);
System.out.println("hashTable: " + table.toString());
table.computeIfAbsent("newPen", k -> 600);
table.computeIfAbsent("newBook", k -> 800);
System.out.println("new hashTable: " + table);
2.6 computeIfPresent
如果指定的密钥的值存在且非空,则尝试计算给定密钥及其当前映射值的新映射。 ??public synchronized V computeIfPresent(K key, BiFunction<? super K, ? super V, ? extends V> remappingFunction)
??使用示例:
Hashtable<String, Integer> wordCount = new Hashtable<>();
wordCount.put("Yiidian", 1);
wordCount.put("for", 2);
wordCount.put("Java", 3);
System.out.println(wordCount);
wordCount.computeIfPresent("Yiidian",(key, val) -> val + 100);
System.out.println( wordCount);
2.7 contains/containsKey/containsValue
1、是否包含某个Value ??public synchronized boolean contains(Object value) 2、是否包含某个key ??public synchronized boolean containsKey(Object key) 3、是否包含某个Value ??public boolean containsValue(Object value)
??使用示例:
Hashtable<String, Integer> wordCount = new Hashtable<>();
wordCount.put("Yiidian", 1);
wordCount.put("for", 2);
wordCount.put("Java", 3);
System.out.println(wordCount.contains(1));
System.out.println(wordCount.containsValue(1));
System.out.println(wordCount.containsKey("PHP"));
2.8 elements
返回此散列表中值的枚举 ??public synchronized Enumeration< V > elements()
??使用示例:
Hashtable<String, Integer> wordCount = new Hashtable<>();
wordCount.put("Yiidian", 1);
wordCount.put("for", 2);
wordCount.put("Java", 3);
for (Enumeration en = wordCount.elements(); en.hasMoreElements();) {
System.out.print(en.nextElement() + " ");
}
2.9 entrySet
返回此地图中包含的映射的Set视图 ??public Set<Map.Entry<K,V>> entrySet()
??使用示例:
Hashtable<String, Integer> wordCount = new Hashtable<>();
wordCount.put("Yiidian", 1);
wordCount.put("for", 2);
wordCount.put("Java", 3);
Set s = wordCount.entrySet();
System.out.println(s);
2.10 equals
比较是否相等 ??public synchronized boolean equals(Object o)
2.11 forEach
对Hashtable中的元素逐个操作 ??public synchronized void forEach(BiConsumer<? super K, ? super V> action)
2.12 get
获取key对应的value ??public synchronized V get(Object key)
2.13 getOrDefault
获取key对应的value,key不存在则返回默认值 ??public synchronized V getOrDefault(Object key, V defaultValue)
2.14 isEmpty
是否为空 ??public synchronized boolean isEmpty()
2.15 keys
返回此散列表中键的枚举 ??public synchronized Enumeration< K > keys()
??使用示例:
Hashtable<String, Integer> wordCount = new Hashtable<>();
wordCount.put("Yiidian", 1);
wordCount.put("for", 2);
wordCount.put("Java", 3);
for (Enumeration en = wordCount.keys(); en.hasMoreElements();) {
System.out.print(en.nextElement() + " ");
}
2.16 keySet
返回此地图中包含的键的Set视图 ??public Set< K > keySet()
??使用示例:
Hashtable<String, Integer> wordCount = new Hashtable<>();
wordCount.put("Yiidian", 1);
wordCount.put("for", 2);
wordCount.put("Java", 3);
Set s = wordCount.keySet();
System.out.println(s);
2.17 merge
如果指定的键尚未与值相关联或与null相关联,则将其与给定的非空值相关联 ??public synchronized V merge(K key, V value, BiFunction<? super V, ? super V, ? extends V> remappingFunction)
??使用示例:
Hashtable<Integer, String> map1 = new Hashtable<>();
map1.put(1, "L");
map1.put(2, "M");
map1.put(3, "N");
Hashtable<Integer, String> map2 = new Hashtable<>();
map2.put(1, "B");
map2.put(2, "G");
map2.put(3, "R");
System.out.println("Hashtable1: " + map1.toString());
System.out.println("Hashtable2: " + map2.toString());
map2.forEach((key, value)-> map1.merge(
key, value,(v1, v2)
-> v1.equalsIgnoreCase(v2) ? v1 : v1 + ", " + v2));
System.out.println("New Hashtable: " + map1);
2.18 put
将指定的 key映射到此 key value中指定的value ??public synchronized V put(K key, V value)
??使用示例:
Hashtable<Integer, String> map1 = new Hashtable<>();
map1.put(1, "L");
map1.put(2, "M");
System.out.println("New Hashtable: " + map1);
2.19 putAll
将所有从指定地图的映射复制到此散列表 ??public synchronized void putAll(Map<? extends K, ? extends V> t)
??使用示例:
Hashtable<Integer, String> map1 = new Hashtable<>();
Hashtable<Integer, String> map2 = new Hashtable<>();
map1.put(1, "L");
map1.put(2, "M");
map2.putAll(map1);
System.out.println( map2);
2.20 putIfAbsent
如果指定的键尚未与值相关联(或映射到 null )将其与给定值相关联并返回 null ,否则返回当前值 ??public synchronized V putIfAbsent(K key, V value)
??使用示例:
Map<String, String> map = new Hashtable<>();
map.put("message", "hello");
System.out.println("Map value before change: "+ map);
String prevvalue = map.putIfAbsent("message", "world");
System.out.println("Returned previous value:"+prevvalue);
System.out.println("Map value after change: "+ map);
2.21 remove
1、从此散列表中删除键(及其对应的值) ??public synchronized V remove(Object key) 2、仅当指定的密钥当前映射到指定的值时删除该条目 ??public synchronized boolean remove(Object key, Object value)
??使用示例:
Map<String, String> map = new Hashtable<>();
map.put("hello", "world");
map.put("say", "hi");
System.out.println(map.remove("hello"));
System.out.println(map.remove("say","hello"));
2.22 replace/replaceAll
1、只有当目标映射到某个值时,才能替换指定键的条目 ??public synchronized V replace(K key, V value) 2、仅当当前映射到指定的值时,才能替换指定键的条目 ??public synchronized boolean replace(K key, V oldValue, V newValue) 3、将每个条目的值替换为对该条目调用给定函数的结果,直到所有条目都被处理或该函数抛出异常 ??public synchronized void replaceAll(BiFunction<? super K, ? super V, ? extends V> function)
??使用示例:
Map<String, String> map = new Hashtable<>();
map.put("hello", "world");
map.put("say", "hi");
System.out.println(map.replace("hello","china"));
System.out.println(map.replace("say","hi","hello"));
map.replaceAll((key, oldValue) -> oldValue+oldValue);
System.out.println(map);
2.23 size
返回此哈希表中的键数 ??public synchronized int size()
2.24 toString
返回Hashtable的字符串形式 ??public synchronized String toString()
??使用示例:
Map<String, String> map = new Hashtable<>();
map.put("hello", "world");
map.put("say", "hi");
System.out.println(map.toString());
2.25 values
返回此地图中包含的值的Collection视图 ??public Collection< V > values()
??使用示例:
Map<String, String> map = new Hashtable<>();
map.put("hello", "world");
map.put("say", "hi");
System.out.println(map.values());
三、Hashtable源码分析
??先看一些变量:
private transient Entry<?,?>[] table;
private transient int count;
private int threshold;
private float loadFactor;
private transient int modCount = 0;
private static final long serialVersionUID = 1421746759512286392L;
3.1 构造方法
public Hashtable() {
this(11, 0.75f);
}
- 2、Hashtable(int initialCapacity)
public Hashtable(int initialCapacity) {
this(initialCapacity, 0.75f);
}
- 3、Hashtable(int initialCapacity, float loadFactor)
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;
table = new Entry<?,?>[initialCapacity];
threshold = (int)Math.min(initialCapacity, MAX_ARRAY_SIZE + 1);
}
- 4、Hashtable(int initialCapacity, float loadFactor)
public Hashtable(Map<? extends K, ? extends V> t) {
this(Math.max(2*t.size(), 11), 0.75f);
putAll(t);
}
public synchronized void putAll(Map<? extends K, ? extends V> t) {
for (Map.Entry<? extends K, ? extends V> e : t.entrySet())
put(e.getKey(), e.getValue());
}
3.2 获取元素
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;
}
3.3 存入元素
public synchronized V put(K key, V value) {
if (value == null) {
throw new NullPointerException();
}
Entry<?,?> tab[] = table;
int hash = key.hashCode();
int index = (hash & 0x7FFFFFFF) % tab.length;
@SuppressWarnings("unchecked")
Entry<K,V> entry = (Entry<K,V>)tab[index];
for(; entry != null ; entry = entry.next) {
if ((entry.hash == hash) && entry.key.equals(key)) {
V old = entry.value;
entry.value = value;
return old;
}
}
addEntry(hash, key, value, index);
return null;
}
private void addEntry(int hash, K key, V value, int index) {
modCount++;
Entry<?,?> tab[] = table;
if (count >= threshold) {
rehash();
tab = table;
hash = key.hashCode();
index = (hash & 0x7FFFFFFF) % tab.length;
}
@SuppressWarnings("unchecked")
Entry<K,V> e = (Entry<K,V>) tab[index];
tab[index] = new Entry<>(hash, key, value, e);
count++;
}
protected void rehash() {
int oldCapacity = table.length;
Entry<?,?>[] oldMap = table;
int newCapacity = (oldCapacity << 1) + 1;
if (newCapacity - MAX_ARRAY_SIZE > 0) {
if (oldCapacity == MAX_ARRAY_SIZE)
return;
newCapacity = MAX_ARRAY_SIZE;
}
Entry<?,?>[] newMap = new Entry<?,?>[newCapacity];
modCount++;
threshold = (int)Math.min(newCapacity * loadFactor, MAX_ARRAY_SIZE + 1);
table = newMap;
for (int i = oldCapacity ; i-- > 0 ;) {
for (Entry<K,V> old = (Entry<K,V>)oldMap[i] ; old != null ; ) {
Entry<K,V> e = old;
old = old.next;
int index = (e.hash & 0x7FFFFFFF) % newCapacity;
e.next = (Entry<K,V>)newMap[index];
newMap[index] = e;
}
}
}
3.4 判断是否包含某个key/value
public boolean containsValue(Object value) {
return contains(value);
}
public synchronized boolean contains(Object value) {
if (value == null) {
throw new NullPointerException();
}
Entry<?,?> tab[] = table;
for (int i = tab.length ; i-- > 0 ;) {
for (Entry<?,?> e = tab[i] ; e != null ; e = e.next) {
if (e.value.equals(value)) {
return true;
}
}
}
return false;
}
public synchronized boolean containsKey(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 true;
}
}
return false;
}
3.5 替换元素
public synchronized V replace(K key, V value) {
Objects.requireNonNull(value);
Entry<?,?> tab[] = table;
int hash = key.hashCode();
int index = (hash & 0x7FFFFFFF) % tab.length;
@SuppressWarnings("unchecked")
Entry<K,V> e = (Entry<K,V>)tab[index];
for (; e != null; e = e.next) {
if ((e.hash == hash) && e.key.equals(key)) {
V oldValue = e.value;
e.value = value;
return oldValue;
}
}
return null;
}
3.6 删除元素
public synchronized V remove(Object key) {
Entry<?,?> tab[] = table;
int hash = key.hashCode();
int index = (hash & 0x7FFFFFFF) % tab.length;
@SuppressWarnings("unchecked")
Entry<K,V> e = (Entry<K,V>)tab[index];
for(Entry<K,V> 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;
}
3.7 获取value集合
public synchronized Enumeration<V> elements() {
return this.<V>getEnumeration(VALUES);
}
private <T> Enumeration<T> getEnumeration(int type) {
if (count == 0) {
return Collections.emptyEnumeration();
} else {
return new Enumerator<>(type, false);
}
}
private <T> Iterator<T> getIterator(int type) {
if (count == 0) {
return Collections.emptyIterator();
} else {
return new Enumerator<>(type, true);
}
}
private class Enumerator<T> implements Enumeration<T>, Iterator<T> {
Entry<?,?>[] table = Hashtable.this.table;
int index = table.length;
Entry<?,?> entry;
Entry<?,?> lastReturned;
int type;
boolean iterator;
protected int expectedModCount = modCount;
Enumerator(int type, boolean iterator) {
this.type = type;
this.iterator = iterator;
}
public boolean hasMoreElements() {
Entry<?,?> e = entry;
int i = index;
Entry<?,?>[] t = table;
while (e == null && i > 0) {
e = t[--i];
}
entry = e;
index = i;
return e != null;
}
@SuppressWarnings("unchecked")
public T nextElement() {
Entry<?,?> et = entry;
int i = index;
Entry<?,?>[] t = table;
while (et == null && i > 0) {
et = t[--i];
}
entry = et;
index = i;
if (et != null) {
Entry<?,?> e = lastReturned = entry;
entry = e.next;
return type == KEYS ? (T)e.key : (type == VALUES ? (T)e.value : (T)e);
}
throw new NoSuchElementException("Hashtable Enumerator");
}
public boolean hasNext() {
return hasMoreElements();
}
public T next() {
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
return nextElement();
}
public void remove() {
if (!iterator)
throw new UnsupportedOperationException();
if (lastReturned == null)
throw new IllegalStateException("Hashtable Enumerator");
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
synchronized(Hashtable.this) {
Entry<?,?>[] tab = Hashtable.this.table;
int index = (lastReturned.hash & 0x7FFFFFFF) % tab.length;
@SuppressWarnings("unchecked")
Entry<K,V> e = (Entry<K,V>)tab[index];
for(Entry<K,V> prev = null; e != null; prev = e, e = e.next) {
if (e == lastReturned) {
modCount++;
expectedModCount++;
if (prev == null)
tab[index] = e.next;
else
prev.next = e.next;
count--;
lastReturned = null;
return;
}
}
throw new ConcurrentModificationException();
}
}
}
3.8 常用方法
方法名 | 含义 | 时间复杂度 |
---|
get(Object key) | 根据key值获取元素 | O(1) | put(K key, V value) | 添加元素 | O(n) | putAll() | 添加Hashtable 中元素 | O(n) | contains(Object value) | 判断是否包含元素 | O(n) | containsValue(Object value) | 判断是否包含元素 | O(n) | containsKey(Object key) | 判断是否包含key | O(1) | replace(K key, V oldValue, V newValue) | 替换元素值 | O(1) | size() | 获取元素数目 | O(1) | isEmpty() | 判断Hashtable 是否为空 | O(1) | remove(Object key) | 根据键值删除元素 | O(n) | clear() | 清空Hashtable | O(n) |
|