HashMap<K,V>
- 此哈希表采用数组+单向链表的方式进行存储。数组中的每个元素,对应哈希算法下的一个哈希值。哈希值重复时,采用链表处理。
/**
* The table, resized as necessary. Length MUST Always be a power of two.
*/
transient Entry[] table;
/**
* The number of key-value mappings contained in this map.
*/
transient int size;
static class Entry<K, V> implements Map.Entry<K, V> {
final K key;
V value;
Entry<K, V> next;
final int hash;
}
- 哈希算法基于key的hashCode的返回值进行运算。通过hash和indexFor两个函数运算,得到table数组中的索引序号。
//获取table数组的索引序号i
int hash = hash(key.hashCode());
int i = indexFor(hash, table.length);
static int hash(int h) {
h ^= (h >>> 20) ^ (h >>> 12);
return h ^ (h >>> 7) ^ (h >>> 4);
}
static int indexFor(int h, int length) {
return h & (length - 1);
}
- 哈希表存储新元素,put方法,先根据hashCode计算索引序号。首先判断当前hash值有没有存在的对象,有则进行重复处理,将当前值放在链表中;没有则在当前的table当前hash值对应的索引位置,如果需要,可能进行table的容量扩充,扩充算法为直接*2。扩容后,hashMap中的各元素会重新存储分布。(hash值算法不变,但是hash值对应的数组索引会发生变化)。
public V put(K key, V value) {
if (key == null)
return putForNullKey(value);
int hash = hash(key.hashCode());
int i = indexFor(hash, table.length);
//当前存在此hash值对象
for (Entry<K, V> e = table[i]; e != null; e = e.next) {
Object k;
if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {
V oldValue = e.value;
e.value = value;
e.recordAccess(this);
return oldValue;
}
}
modCount++;
//不存在此hash值对象
addEntry(hash, key, value, i);
return null;
}
void addEntry(int hash, K key, V value, int bucketIndex) {
Entry<K, V> e = table[bucketIndex];
table[bucketIndex] = new Entry<K, V>(hash, key, value, e);
if (size++ >= threshold)
//进行扩容处理,过程中,整个hashMap会重新分布。
resize(2 * table.length);
}
void resize(int newCapacity) {
Entry[] oldTable = table;
int oldCapacity = oldTable.length;
if (oldCapacity == MAXIMUM_CAPACITY) {
threshold = Integer.MAX_VALUE;
return;
}
Entry[] newTable = new Entry[newCapacity];
transfer(newTable);
table = newTable;
threshold = (int) (newCapacity * loadFactor);
}
void transfer(Entry[] newTable) {
Entry[] src = table;
int newCapacity = newTable.length;
for (int j = 0; j < src.length; j++) {
Entry<K, V> e = src[j];
if (e != null) {
src[j] = null;
do {
Entry<K, V> next = e.next;
int i = indexFor(e.hash, newCapacity);
e.next = newTable[i];
newTable[i] = e;
e = next;
} while (e != null);
}
}
}
- 哈希表获取存储的元素,get方法。先根据hashCode计算索引序号。然后顺序逐一比较key值,等号比较和equal比较,查询到需要的对象值。
public V get(Object key) {
if (key == null)
return getForNullKey();
int hash = hash(key.hashCode());
for (Entry<K, V> e = table[indexFor(hash, table.length)]; e != null; e = e.next) {
Object k;
if (e.hash == hash && ((k = e.key) == key || key.equals(k)))
return e.value;
}
return null;
}
- HashTable扩展自Dictionary<K, V>,而非相关的Map接口。同时HashTable是线程同步的。
- LinkedHashMap是基于HashMap的有序哈希表。其中存在一个双向循环链表,元素按照加入到哈希表中的顺序排列。
void init() {
header = new Entry<K, V>(-1, null, null, null);
header.before = header.after = header;
}
void createEntry(int hash, K key, V value, int bucketIndex) {
HashMap.Entry<K, V> old = table[bucketIndex];
Entry<K, V> e = new Entry<K, V>(hash, key, value, old);
table[bucketIndex] = e;
//循环链表尾部加入一个新的元素
e.addBefore(header);
size++;
}
- ConcurrentHashMap使用了多个segments,每个Segment中使用了类似HashMap的存储结构,进行了存储,不同的是,对于put操作,使用了ReentrantLock进行锁定操作。get操作,没有锁操作。此哈希表,在保证线程安全的前提下,如果存储值在当前hash算法下不过于集中到某个segment中,此容器具有不错的性能。
//ConcurrentHashMap的put方法
public V put(K key, V value) {
if (value == null)
throw new NullPointerException();
int hash = hash(key.hashCode());
return segmentFor(hash).put(key, hash, value, false);
}
//Segment的put方法
V put(K key, int hash, V value, boolean onlyIfAbsent) {
lock();
try {
int c = count;
if (c++ > threshold) // ensure capacity
rehash();
HashEntry<K, V>[] tab = table;
int index = hash & (tab.length - 1);
HashEntry<K, V> first = tab[index];
HashEntry<K, V> e = first;
while (e != null && (e.hash != hash || !key.equals(e.key)))
e = e.next;
V oldValue;
if (e != null) {
oldValue = e.value;
if (!onlyIfAbsent)
e.value = value;
} else {
oldValue = null;
++modCount;
tab[index] = new HashEntry<K, V>(key, hash, first, value);
count = c; // write-volatile
}
return oldValue;
} finally {
unlock();
}
}
分享到:
相关推荐
<br>第1章 Java基础 <br>1.1 转换基本数据类型 <br>1.2 Java的运算符 <br>1.3 控制程序的流程 <br>1.4 计算阶乘 <br>1.5 实现命令行程序 <br>第2章 Java面向对象程序设计 <br>2. 1 复数类 <br>2. 2 equals.chashCode...
- **集合框架**: 研究ArrayList、LinkedList、HashMap、HashSet等数据结构的实现。 - **I/O流**: 理解字节流、字符流、缓冲流、对象序列化等概念。 - **网络编程**: 学习Socket通信,HTTP、FTP协议的实现。 - **国际...
2. **集合框架**:`java.util`包中的`ArrayList`、`LinkedList`、`HashMap`、`HashSet`等数据结构的实现,这些是日常编程中最常用的工具。源码可以帮助理解它们的性能特性,比如插入、删除、查找的时间复杂度。 3. ...
深入理解JDK 1.6的源码对于Java开发者来说至关重要,因为它揭示了语言核心库的工作原理,有助于优化代码、理解和解决潜在问题。 1. **Java虚拟机(JVM)**:JDK 1.6中的JVM是Java程序执行的基础,它的主要职责是...
6. **集合框架**:`java.util`包中的集合类,如ArrayList、HashMap、LinkedList等,其内部实现细节对于理解数据结构和算法有很大帮助。 7. **I/O流**:`java.io`和`java.nio`包提供了丰富的输入/输出流接口和类,...
源码分析能够揭示ArrayList、HashMap、HashSet等数据结构的内部实现,帮助理解其性能特点和适用场景。 8. **网络编程** JDK 1.6的Socket和ServerSocket类提供了基础的网络通信功能。通过源码,我们可以学习到连接...
`java.util`中的ArrayList和HashMap,是常用数据结构的实现;还有`java.io`中的File类,用于文件操作。 5. **launcher**: Java启动器(Java Launcher)是JVM(Java Virtual Machine)启动应用程序的关键组件。在JDK...
在JDK 1.6中,你可以在这里找到如Object、String、ArrayList、HashMap等基础类的源代码,这些是构建任何Java程序的基础。 **6. org 文件夹** org目录通常包含开源组织或标准组织提供的库。在JDK 1.6中,org可能包含...
通过阅读这些类的源码,可以学习到各种设计模式,如工厂模式、单例模式、装饰器模式等,同时也能理解Java内置数据结构(如`ArrayList`, `HashMap`)的实现细节,这对于提升编程技能和解决问题具有极大帮助。...
- **选择主题**: 针对特定感兴趣的领域,如并发、网络编程或数据结构,深入研究相关源码。 - **阅读文档**: 结合Javadoc了解类和方法的用途和参数,这是理解源码的基础。 - **调试与实验**: 使用IDE的源码浏览功能...
6. **输入输出流**:Java的I/O流系统是处理数据传输的关键,源码会涵盖文件读写、网络通信、序列化等场景,让你了解InputStream、OutputStream、Reader、Writer等类的使用。 7. **反射机制**:反射是Java的高级特性...
通过源码,我们可以学习这些类和接口的实现,例如ArrayList和HashMap的工作原理,线程同步的细节,以及Socket通信的底层实现。 4. **异常处理**: 源码中展示了Java如何处理异常,包括检查性异常和运行时异常。理解...
这些类的源码展示了如何实现数据结构和算法,对于提升算法和数据结构理解有很大帮助。 10. **异常处理** `java.lang.Throwable`及其子类定义了Java的异常处理机制。通过查看源码,我们可以了解到异常的抛出、捕获...
`java.util.ArrayList`和`java.util.HashMap`是常用的集合类,它们的实现涉及动态数组和哈希表的数据结构;`java.io`包下的类则涵盖了输入输出流的处理,如`FileInputStream`和`PrintWriter`。 通过阅读和学习这些...
再者,JDK1.8对HashMap和HashSet等数据结构进行了优化,尤其是并发性能的提升。例如,ConcurrentHashMap在1.8版本中采用了分段锁策略,提高了并发访问的效率。此外,新版本的TreeMap和TreeSet使用了Fork/Join框架下...
在源码中,你可以看到`java.lang`、`java.util`、`java.io`等包中的各种基础类是如何实现的,例如`String`、`ArrayList`、`HashMap`等常用数据结构。 首先,`java.lang`包包含了Java语言的基础类和接口,如`Object`...
Java Development Kit (JDK) 1.8 是Java编程语言的一个关键版本,它引入了许多重要的特性和改进。...对于希望深入理解Java并成为更好的开发者的程序员来说,JDK 1.8源码的探索是一次不可或缺的学习之旅。
"Android-jdk源码阅读"这个主题聚焦于分析Java标准库中的`TreeMap`类,这是一个基于红黑树数据结构实现的有序映射。在这个主题中,我们将探讨`TreeMap`的内部工作原理,特别是它如何利用红黑树来实现高效的插入、...
通过阅读和分析JDK 1.7的源码,我们可以深入了解这些类和接口的实现细节,这对于优化代码性能、排查问题以及设计自己的数据结构和算法都有很大帮助。同时,这也是学习Java语言和提升编程能力的重要途径。
java.util.*包中的ArrayList、HashMap等集合类,是日常开发中频繁使用的数据结构;而java.io.*包则涵盖了输入/输出操作,包括文件、网络和内存流。 最后,org目录通常用于存放开源组织或标准组织的代码,如org.w3c....