一.前言
- HashMap和Hashtable大部分算法是相同的,容器学习一:HashMap源码分析
对HashMap源码进行了分析,可以先阅读它。
- 相同的算法部分不再分析,本文主要考虑Hashtable和HashMap的不同之处。
二.Hashtable成员变量
private transient Entry[] table;
// 等同于HashMap里面的size
private transient int count;
private int threshold;
private float loadFactor;
private transient int modCount = 0;
三.Hashtable构造函数
// DEFAULT_INITIAL_CAPACITY=11,DEFAULT_LOAD_FACTOR还是0.75
public Hashtable() {
this(11, 0.75f);
}
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;
// 直接用initialCapacity初始化,并没有要求用2的次方指来初始化
this.loadFactor = loadFactor;
table = new Entry[initialCapacity];
threshold = (int) (initialCapacity * loadFactor);
}
四.hash算法和index算法
//自己拿到key的hash值
int hash = key.hashCode();
//计算index做了求模运算。
int index = (hash & 0x7FFFFFFF) % tab.length;
五.取数据
public synchronized V get(Object key) {
Entry tab[] = table;
//Hashtable所有的方法都不接受null的key,所有的地方都是不判断就直接key.hashCode();
int hash = key.hashCode();
int index = (hash & 0x7FFFFFFF) % tab.length;
for (Entry<K, V> e = tab[index]; e != null; e = e.next) {
//同HahsMap相比没有判断e.key==key,
//Hahstable里面,e.key.equals(key)就够了,在key不为null的前提下e.key==key是e.key.equals(key)的充分不必要条件
if ((e.hash == hash) && e.key.equals(key)) {
return e.value;
}
}
return null;
}
六.存数据
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;
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++;
//HashMap先加Entry再决定是否扩容,Hahstable再判断大小在加Entry
//我还是喜欢这样比较:count + 1 > threshold
if (count >= threshold) {
rehash();
tab = table;
index = (hash & 0x7FFFFFFF) % tab.length;
}
// Creates the new entry.
Entry<K, V> e = tab[index];
tab[index] = new Entry<K, V>(hash, key, value, e);
count++;
return null;
}
protected void rehash() {
int oldCapacity = table.length;
Entry[] oldMap = table;
int newCapacity = oldCapacity * 2 + 1;
Entry[] newMap = new Entry[newCapacity];
modCount++;
threshold = (int) (newCapacity * loadFactor);
table = newMap;
//和HashMap算法是一样的,建议看HashMap里面的写法好理解点。
for (int i = oldCapacity; i-- > 0;) {
for (Entry<K, V> old = oldMap[i]; old != null;) {
Entry<K, V> e = old;
old = old.next;
int index = (e.hash & 0x7FFFFFFF) % newCapacity;
e.next = newMap[index];
newMap[index] = e;
}
}
}
七.总结
|
HashMap |
Hashtable |
出现时间 |
JDK1.2,所以代码质量更高,更容易明白 |
JDK1.0 |
并发控制 |
没有考虑并发 |
所有方法都加了synchronized,即使有些我认为不需要的也加了 |
是否接受值为null的Key 或Value
|
接受 |
不接收。put等方法里面:if (value == null) {
显示throw new NullPointerException();
};int hash=key.hashcode隐示throw NullPointerException(); |
初始化table |
缺省容量16。初始化时可以指定initial capacity,若不是2的次方,HashMap将选取第一个大于initial capacity 的2的次方值作为其初始长度 |
缺省容量11。初始化时可以指定initial capacity |
扩容 |
添加Entry后判断是否该扩容。扩容至2*oldCapacity |
先判断是否扩容再添加Entry。扩容至2*oldCapacity + 1
|
数据遍历的方式 |
Iterator |
Iterator 和 Enumeration
|
是否支持fast-fail
|
支持fast-fail |
用Iterator遍历,支持fast-fail
用Enumeration不支持fast-fail.
|
hash算法和index算法 |
优于Hashtable,通过对Key的hash做移位运算和位的与运算,使其能更广泛地分散到数组的不同位置
|
当数组长度较小,并且Key的hash值低位数值分散不均匀时,不同的hash值计算得到相同下标值的几率较高
|
实现和继承 |
extends AbstractMap 骨架结构的体现,代码质量上去了 |
extends Dictionary implements Map 直接实现Map接口。多基础了一个已过时的经Dictionary类,就不用去管了 |
|
|
|
分享到:
相关推荐
【Java容器之Hashtable源码分析】 在Java编程中,`Hashtable`是一个古老的容器类,它继承自`Dictionary`接口,并实现了`Map`接口,同时也实现了`Cloneable`和`Serializable`接口。`Hashtable`与`HashMap`类似,都是...
这本书也不适合带领你学习面向对象(Object Oriented)技术 — 是的,STL 与面向对象没有太多关连。本书前言清楚说明了书籍的定位和合适的读者,以及各类基础读物。如果你的Generic Programming/STL实力足以阅读本书...
这种设计使得它在处理高并发场景时,性能远超传统的线程安全容器如`Hashtable`。在实际开发中,`ConcurrentHashMap`常被用于构建高性能的并发数据结构,例如在Spring框架中,就广泛使用`ConcurrentHashMap`作为缓存...
源码分析 ArrayList 是一个基于动态数组实现的 List 实现类。它实现了 RandomAccess 接口,因此支持随机访问。ArrayList 的默认大小为 10,添加元素时使用 ensureCapacityInternal() 方法来保证容量足够,如果不够...
### HashMap源码分析 #### 一、概述 `HashMap`是Java编程语言中非常重要的一个数据结构,它属于`java.util`包的一部分,是`Map`接口的一个具体实现类。`HashMap`允许存储键值对,并且支持使用`null`作为键或值,这...
源码分析能让我们明白线程管理和同步原语的工作原理。 5. **System.Collections**: 包含各种集合类,如ArrayList、Dictionary和Hashtable。源码中可以找到如何高效存储和检索数据的实现。 三、基础结构与设计原则 ...
STL,全称为Standard Template ...通过分析源码,我们可以学习到如何平衡空间和时间复杂度,以及如何设计和实现高效的数据结构和算法。这对于任何想要深入理解C++和提升编程能力的人来说都是极其宝贵的学习资源。
#### 第二章:JDK源码分析 ##### Unsafe - **限制**:`Unsafe`类提供了对底层内存和机器级别的访问操作,但由于其潜在的安全风险,通常不推荐直接使用。 - **API**:主要包括内存读写、同步原语操作等。 - **获取...
6.1.1 算法分析与复杂度表示 o( ) 286 6.1.2 stl算法总览 288 6.1.3 mutating algorithms - 会改变操作对象之值 291 6.1.4 nonmutating algorithms - 不改变操作对象之值 292 6.1.5 stl算法的一般形式 292 6.2 ...
3. **同步容器**:`Vector`, `HashTable`等是早期的同步容器,它们使用`synchronized`关键字实现线程安全,但性能较低。后来出现了`ArrayList`, `HashMap`等非同步容器,配合`synchronized`块或`Lock`进行同步操作。...
根据提供的文件信息,我们可以分析出这是一段Java代码,它涉及到了一个简单的仓库管理系统的设计与实现。接下来,我们将深入解析这段代码所包含的关键知识点,并基于这些知识点进行拓展讲解。 ### 关键知识点一:类...
#### 六、JDK源码分析 深入理解JDK源码可以帮助开发者更好地理解Java语言的底层实现。 - **重要源码分析**: - List、Map、Set等集合类的实现细节。 - 多线程相关的类如`Thread`、`Lock`等。 - I/O相关的类如`...
书中不仅分析了STL的源码,还涉及到了一些高级的实现技巧。在阅读这本书之前,读者需要具备一定的C++基础和对泛型编程(Generic Programming)有一定的了解。因为这本书并不适合于初学者,它更偏向于有经验的开发者...
本文将深入探讨集合框架的使用方法,包括其基本概念、主要类库以及常见操作,同时也会提及一些源码分析和实用工具。 一、集合框架概述 Java集合框架是一个统一的接口体系,它定义了各种数据结构(如列表、队列、...
通过学习这部分源代码,你可以理解如何高效地实现这些基础操作,并学习到算法设计和分析的技巧。 2. **deque**:双端队列(deque)是一种随机访问的数据结构,允许在两端进行插入和删除操作。相比于数组,它在两端...
hashmap源码 to-be-architect to be a Java architect,you should learn these.This page is updated irregularly. Java基础 深入分析 Java SPI 机制和原理 并发编程专题 Executors线程池 线程池ThreadPoolExecutor...
- **同步容器**:如`Hashtable`和`Vector`提供了线程安全的实现,但这种实现通常会影响性能。 - **可重入锁**:使用`synchronized`关键字可以实现简单的线程安全,但更灵活的方式是使用`ReentrantLock`等高级锁机制...
这个"JCFInternals.zip"可能包含源码分析、实战示例等内容,帮助开发者深入掌握Java集合框架的内部机制,从而更好地利用这些工具来编写高效、可靠的代码。通过学习和实践,开发者将能够根据具体需求选择合适的集合...