一.前言
- 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集合容器知识点详解 #### 一、集合容器概述 - **定义**:集合容器是Java平台提供的标准组件,主要用于存储对象。...通过本篇文章的学习,希望读者能够更好地理解和应用Java集合容器,提升编程技能。
- `Hashtable`:键值对存储。 - `Vector`:可变大小的数组。 #### Collection interface(容器类接口) - **定义**:定义容器类共同的操作。 - **目的**: - 提供一致性的编程模型。 - 支持不同的容器实现。 #...
- **Hashtable**:表示哈希表。 - **Input**:表示输入。 - **JointDrive**:表示关节驱动。 - **JointLimits**:表示关节限制。 - **JointMotor**:表示关节马达。 - **JointSpring**:表示关节弹簧。 - **Keyframe...
### hashMap和hashTable的区别 #### 一、简介与基本概念 `HashMap` 和 `HashTable` 都是 Java 集合框架中非常重要的数据结构,它们都实现了 `Map` 接口,用于存储键值对。尽管它们在功能上有很多相似之处,但在...
#### 二、Vector, ArrayList, LinkedList 区别 1. **存储结构**: - **Vector** 和 **ArrayList**:采用数组实现,方便随机访问。 - **LinkedList**:采用链表实现,适合频繁的插入和删除操作。 2. **线程安全**...
**二、Hashtable属性** Hashtable的主要属性包括: 1. `table`:这是一个内部类`Entry`的数组,存储键值对。 2. `count`:记录哈希表中键值对的数量。 3. `threshold`:扩容的阈值,等于容量乘以负载因子。 4. `...
Hashtable hashtable = new Hashtable(); hashtable.put("x", "12345"); hashtable.put("y", "67890"); hashtable.put("a", "abcde"); System.out.println(hashtable.get("a")); ``` 这段代码中,`Hashtable`中存储...
- **IOC容器**:管理对象生命周期和依赖关系。 - **AOP**:面向切面编程,分离关注点。 - **模块化**:提供多种模块,如Web、Data Access等。 ##### 事务概述 - **ACID特性**:原子性、一致性、隔离性、持久性。 -...
- **描述**:`Hashtable` 是 Java 中最早的键值对映射容器之一。 - **应用场景**:适用于需要快速查找数据的情况,例如作为查找表。 - **特点**:线程安全、不允许 null 键和 null 值。 3. **Character 流与 ...
### 二、常用的集合类 #### 1. Map接口和Collection接口 - **Map接口**:表示键值对映射关系的集合。 - **Collection接口**:表示单个对象的集合。 #### 2. Collection接口的子接口 - **Set接口**:不允许包含...
#### 二、Java语言基础 ##### 1. 数据类型与变量 Java 支持多种数据类型,包括基本数据类型(如 `int`, `double`, `char` 等)和引用数据类型(如类、数组等)。 - **基本数据类型**:例如 `int` 用于整数,`...
### Hashtable与HashMap的区别详解 #### 一、基本概念与历史背景 在Java编程语言中,`Hashtable` 和 `HashMap` 都是用来存储键值对的数据结构。这两种数据结构虽然相似,但是在实现细节上存在显著差异。 1. **...
#### 二、基本数据类型与String **1. String是否为基本数据类型?** - **结论**:不是。 - **解释**:Java中的基本数据类型包括`byte`、`short`、`int`、`long`、`float`、`double`、`char`、`boolean`。 - **...
- `s:hashtable`:遍历Hashtable对象。 - `s:if`和`s:else`:条件判断,可以根据条件显示内容。 6. **Include标签** - `s:include`:包含其他JSP或Freemarker模板。 7. **Message标签** - `s:messages`:显示...
- **JavaEE**: 企业版,除了标准版的功能外,还包含了Web容器、EJB容器等企业级功能。 - **JavaME**: 微小版,主要用于嵌入式设备和移动设备。 #### 三十九、JDK、JRE、JVM的区别 - **JDK**: Java Development Kit...
- **dentry_hashtable**: `dentry`的哈希表,用于快速查找文件名到`inode`的映射。 - **super_blocks**: `super_block`的哈希表,用于快速查找文件系统。 #### 总结 这些数据结构共同构成了Linux VFS的核心框架,...
### HashMap与HashTable的区别 在Java编程语言中,`HashMap`和`HashTable`是两种非常重要的数据结构,它们都实现了`Map`接口,并提供了键值对的存储方式。这两种数据结构虽然相似,但在实现细节和使用场景上存在...
- **定义**:用于存储数据的容器。 - **定义格式**:数据类型 变量名 = 初始值; - **注意事项**: - 在使用变量前必须先声明。 - 数据类型与变量存储的数据类型一致。 - 同一作用域内不能重复声明相同变量。 ###...
- **字节流**:处理字节数据,通常用于二进制文件的读写。 - **字符流**:处理字符数据,通常用于文本文件的读写。 #### 5. 阻塞 I/O 模型 - **特点**:每次I/O操作必须等待完成才能继续执行后续操作。 #### 6. 非...