深入学习java集合:Hashtable<K,V>实现
来源:互联网 发布:数据库获取当前时间 编辑:程序博客网 时间:2024/06/05 04:49
1、Hashtable类图
从中可以看出HashTable继承Dictionary类,实现Map接口。其中Dictionary类是任何可将键映射到相应值的类(如 Hashtable)的抽象父类。每个键和每个值都是一个对象。在任何一个 Dictionary 对象中,每个键至多与一个值相关联。Map是"key-value键值对"接口。
Hashtable是一个古老的 Map 实现类,一般不建议使用 ,Hashtable是一个线程安全的 Map 实现。Hashtable不允许使用 null 作为 key 和 value,与 HashSet集合不能保证元素的顺序的顺序一样,Hashtable也不能保证其中 key-value 对的顺序。Hashtable 判断两个 Key 相等的标准是:两个 Key 通过 equals 方法返回 true,hashCode值也相等。
2、HashTable构造实现以及重要方法
HashTable采用"拉链法"实现哈希表,它定义了几个重要的参数:table、count、threshold、loadFactor、modCount。
/**
* The hash table data.
*/
private transient Entry<K,V>[] table;
2)构造器
HashTable提供了4个不同的构造器
// 构造一个初始大小为initialCapacity,装载因子为loadFactor的空的HashTable
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]; //初始化table,获得大小为initialCapacity的table数组
threshold = (int)Math.min(initialCapacity * loadFactor, MAX_ARRAY_SIZE + 1); //计算阀值
initHashSeedAsNeeded(initialCapacity); //初始化HashSeed值
}
// 构造一个初始大小为initialCapacity,装载因子为默认的0.75的空的HashTable
public Hashtable(int initialCapacity) {
this(initialCapacity, 0.75f);
}
//默认的无参数构造器,默认的初始大小为16,装载因子为0.75
public Hashtable() {
this(11, 0.75f);
}
3) hash(Object k): int 就算hash值的函数
private int hash(Object k) {
// hashSeed will be zero if alternative hashing is disabled.
return hashSeed ^ k.hashCode();
}
4) put(key: K, value: V): V 添加将指定 key 映射到此哈希表中的指定 value方法
可以看到该方法加了同步处理 ,首先 计算key的hash值,根据hash值获得key在table数组中的索引位置,然后迭代该key处的Entry链表,若该链表中存在一个这个的key对象,那么就直接替换其value值即可,否则在将改key-value节点插入该index索引位置处。
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); //计算key的hash值
int index = (hash & 0x7FFFFFFF) % tab.length; //计算在table数组中的索引下标,也就是对应的桶
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;
}
5) get(key: Object): V 获取HashTable中,key对应的value方法
// 处理过程就是计算key的hash值,判断在table数组中的索引位置,然后迭代链表,匹配直到找到相对应key的value,若没有找到返回null。 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;
}
6 )rehash(): void HashTable 再hash方法
HashTable的扩容操作是在put方法中,如果需要向table[]中添加Entry元素,会首先进行容量校验,如果容量已经达到了阀值,HashTable就会进行扩容处理rehash()。
protected void rehash() {
int oldCapacity = table.length;
Entry<K,V>[] oldMap = table;
// overflow-conscious code
int newCapacity = (oldCapacity << 1) + 1; //新容量=旧容量 * 2 + 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]; //构建新的大小等于newCapacity的HashTable
modCount++;
threshold = (int)Math.min(newCapacity * loadFactor, MAX_ARRAY_SIZE + 1); //重新计算阀值
boolean rehash = initHashSeedAsNeeded(newCapacity); //重新计算Hash种子
table = newMap;
for (int i = oldCapacity ; i-- > 0 ;) { //依次将原来的元素拷贝到新的Hashtable中
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;
}
}
}
3、HashTable与HashMap区别
HashTable和HashMap存在很多的相同点,但是他们还是有几个比较重要的不同点。
第一:我们从他们的定义就可以看出他们的不同,HashTable基于Dictionary类,而HashMap是基于AbstractMap。Dictionary是什么?它是任何可将键映射到相应值的类的抽象父类,而AbstractMap是基于Map接口的骨干实现,它以最大限度地减少实现此接口所需的工作。
第二:HashMap可以允许存在一个为null的key和任意个为null的value,但是HashTable中的key和value都不允许为null。当HashMap遇到为null的key时,它会调用putForNullKey方法来进行处理。对于value没有进行任何处理,只要是对象都可以。
第三:Hashtable的方法是同步的,而HashMap的方法不是。所以有人一般都建议如果是涉及到多线程同步时采用HashTable,没有涉及就采用HashMap,但是在Collections类中存在一个静态方法:synchronizedMap(),该方法创建了一个线程安全的Map对象,并把它作为一个封装的对象来返回,所以通过Collections类的synchronizedMap方法是可以我们你同步访问潜在的HashMap。
0 0
- 深入学习java集合:Hashtable<K,V>实现
- 深入学习java集合:HashMap<K,V>实现
- 深入学习java集合:LinkedHashMap<K,V>实现
- Java集合之Hashtable<K,V>,TreeMap<K,V>,HashMap<K,V>自动排序
- 深入学习java并发编程:ConcurrentHashMap<K, V>实现
- 深入Java集合学习系列:Hashtable的实现原理
- 深入Java集合学习系列:Hashtable的实现原理
- 深入Java集合学习系列:Hashtable的实现原理
- 深入Java集合学习系列:Hashtable的实现原理
- 深入Java集合源码学习系列:Hashtable的实现原理
- 深入Java集合学习系列:Hashtable的实现原理
- Java集合Map<K,V>
- 深入java集合系列之Hashtable
- 深入Java集合学习系列:TreeMap实现
- 深入学习java集合:ArrayList<E>实现
- 深入学习java集合:LinkedList<E>实现
- 深入学习java集合:HashSet<E>实现
- 深入学习java集合:TreeSet<E>实现
- 深入学习java集合:LinkedHashMap<K,V>实现
- Win8风格界面效果
- Unity Oculus开发注意事项
- javax.persistence.Table.indexes()[Ljavax/persistence/Index;
- 睡眠理发师问题
- 深入学习java集合:Hashtable<K,V>实现
- 简单配置yum源安装软件
- poj3273 Monthly Expense(二分)
- 多维数组应该注意的几点
- CodeForces-505B-Mr. Kitayuta's Colorful Graph(弗洛伊德)
- poj 3460 Booksort
- Struts2表单验证、模型驱动、防重复提交、数据回显
- 快速排序 过程图解
- IMF 自定义 IMFTimer、IMFTimerTask