http://www.hetaoblog.com/%E8%AF%B4%E4%B8%80%E8%AF%B4java%E9%87%8C%E9%9D%A2%E7%9A%84hashcode4-hashmap%E4%BB%A3%E7%A0%81%E5%88%86%E6%9E%901/
现在进入hashcode第4篇,HashMap代码分析,
先看到这个类的成员变量,有下面8个,
static final int DEFAULT_INITIAL_CAPACITY = 16; // 默认的容量
static final int MAXIMUM_CAPACITY = 1 << 30; // 最大容量, 取到2^30
static final float DEFAULT_LOAD_FACTOR = 0.75f; // 默认的load factor,
transient Entry[] table; // 这里,用一个数组存储了真正的Entry,Entry里面有成员k和v
transient int size; // 大小
int threshold; // 容量限制
final float loadFactor; // 实际load factor
transient volatile int modCount;
重点:
* 实际的kv数据用一个entry类,存放在一个数组里面
下面看下默认的构造函数
public HashMap() {
this.loadFactor = DEFAULT_LOAD_FACTOR;
threshold = (int)(DEFAULT_INITIAL_CAPACITY * DEFAULT_LOAD_FACTOR);
table = new Entry[DEFAULT_INITIAL_CAPACITY]; // 构造Entry表格
init(); // 这个函数是空的,可以忽略
}
下面是put函数,这段函数的主要意思:
1. 因为HashMap允许null(而HashTable不允许), 所以如果是null的话先固定放到第一个
2. 对对象的hashcode()再做一次hash,然后取索引,这里略有点故事,一般hash表的数组长度应该是质数,而jdk里面的HashMap选了2的指数作为数组大小,这里要做一次保护,这个下次可以单独写一点
3. 接下来,取到这个哈希数组里面的索引这项,然后对这项上的链表进行遍历,看看有没有存在一个key,和新放进来的元素hash值一样,并且(是同一个元素或者equals方法也返回相等)(这就是为什么Object.hashcode()里面会有那样的约定,如果你违法了那边的约定,假设两个对象equals返回true,本质上是同一个对象,但是hashcode不一样的话,那两次put会放到两个不同的地方了;
如果有的话,说明是同一个key对象,用新的value替换老的value,并且返回老的value
4. 如果不存在同一个key,那么就把该元素加入到这个哈希数组的这个位置(就是通过hashcode()再做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);
for (Entry 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++;
addEntry(hash, key, value, i);
return null;
}
这里具体的addEntry代码如下:
void addEntry(int hash, K key, V value, int bucketIndex) {
Entry e = table[bucketIndex];
table[bucketIndex] = new Entry(hash, key, value, e);
if (size++ >= threshold)
resize(2 * table.length);
}
以及Entry的实现和构造函数:
static class Entry implements Map.Entry {
final K key;
V value;
Entry next;
final int hash;
/**
* Creates new entry.
*/
Entry(int h, K k, V v, Entry n) {
value = v;
next = n;
key = k;
hash = h;
}
可以看到,
1. 新添加的元素被放到了哈希数组这个位置上面的链表的第一个;
2. 如果HashMap里面存放的总的元素个数超过了threshold(也就是capacity*loadfactor), 那么就把存放数据的数组扩大一倍
这里面是说总的元素个数,下面的代码是会打印2的。其实就是已经存了比较多的数据了,基本上直接hash一次访问到的概率比较小了,很可能很多元素都要继续通过访问后面的Entry链表来得到,效率就下降了,Hash的优势已经不那么明显了,所以把表格扩大一倍,把原来的元素根据hash值重新做一次索引和分布,尽可能让链表缩短,提高访问效率
Map m = new HashMap();
m.put("BB", 10);
m.put("Aa", 11);
System.out.println(m.size());
分享到:
相关推荐
HashMap是Java编程语言中一种非常重要的数据结构,它属于Java集合框架的一部分,主要用来存储键值对(key-value pairs)。HashMap在内部实现上基于哈希表,提供了快速的插入、删除和查找操作,通常时间复杂度为O(1)...
在Java编程语言中,`HashMap`是`java.util`包中的一个核心类,它属于集合框架的一部分,主要用于存储键值对的数据结构。`HashMap`基于哈希表(散列表)实现,提供了快速的插入、删除和查找操作,平均时间复杂度为O(1...
Java HashMap 类详解 本资源详细介绍了 Java 中的 HashMap 类...本资源详细介绍了 Java 中的 HashMap 类,包括其实现机制、Hash 存储机制、集合存储机制等方面的知识点,为大家提供了一个详细的 Java HashMap 类详解。
Hashcode是一个关键的概念,它是Java中的一个方法,用于将对象映射到一个整数值,通常用于哈希表的实现。每个对象都有一个唯一的哈希码,除非两个对象完全相等(equals()返回true),否则它们的哈希码必须不同。如果...
在Java编程语言中,集合框架是开发者日常工作中不可或缺的一部分,HashMap作为其中的重要成员,它的实现原理对于理解Java性能优化和数据结构有深远的意义。HashMap是一个基于哈希表的数据结构,它实现了Map接口,...
总的来说,Clevel-HashMap是Java并发编程中不可或缺的数据结构,它的设计理念和实现策略为多线程环境下的高效数据存储提供了解决方案。通过深入理解其内部机制,开发者可以更好地利用它来优化应用程序的性能。
在Java编程语言中,`hashCode()`和`equals()`方法是对象身份验证的关键组成部分,它们主要用于对象的比较和哈希表(如HashMap、HashSet等)的操作。理解这两个方法的工作原理对于编写高效和可靠的代码至关重要。 ...
Java中的HashMap是一种基于散列机制的Map接口的实现,它允许我们存储键值对。键是唯一的,而值可以重复。HashMap在处理数据时非常高效,因为其操作的时间复杂度接近于O(1)。这是通过使用散列函数将键映射到相应的...
总之,理解并正确重写 `equals()` 和 `hashCode()` 方法对于编写高质量的Java代码至关重要,这直接影响到对象比较的逻辑以及使用哈希表的数据结构的效率。通过遵循上述原则和最佳实践,我们可以确保对象的比较行为...
文件中示例代码使用***(即2^31)作为模数,该数值是JavaScript安全整数范围的一半,因为JavaScript的Number类型是以IEEE 754标准的双精度浮点数实现的,其能安全表示的最大整数为2^53-1。 5. **取模优化**:为了...
在 Java 中,哈希码经常被用于实现散列表(如 `HashMap` 和 `HashSet`)。为了确保散列表的正确性,重写 `equals` 方法时,通常也需要重写 `hashCode` 方法,以保证两个相等的对象拥有相同的哈希码。 在示例代码中...
理解HashMap的这些基本概念和工作原理,对于Java开发者来说,不仅有助于在面试中脱颖而出,还能在日常开发中合理选择和使用数据结构,提高代码的性能和可维护性。深入学习和实践HashMap源码,能够帮助我们更好地理解...
《Effective Java》是Java开发领域的一本经典著作,由Joshua Bloch撰写,书中提出了一系列编程最佳实践和设计模式,帮助开发者写出更高效、更可靠、更易于维护的Java代码。配套代码`effective-java-examples-master`...
哈希映射(HashMap)是Java编程语言中广泛使用的数据结构之一,主要提供键值对的存储和查找功能。HashMap的实现基于哈希表的概念,它通过计算对象的哈希码来快速定位数据,从而实现了O(1)的平均时间复杂度。在深入...
- 了解如何编写干净、可读性强的代码是成为一名优秀Java开发者的必备技能之一。这包括遵循良好的命名约定、使用注释来解释复杂的逻辑、避免代码重复(DRY原则)等。 - 使用合适的工具和技术进行单元测试和集成测试也...
深入理解HashMap的工作原理对于提升Java开发的效率和写出高效的代码至关重要。以下是对HashMap工作原理的详细解析。 HashMap基于哈希表(也称为散列表)实现,它的核心思想是通过对象的哈希值来快速定位数据。当向...
哈希码(HashCode)在Java编程中扮演着重要的角色,特别是在数据结构如哈希表(HashMap、HashSet等)中。哈希码是一个整数值,它代表了对象的唯一标识。当我们谈论“hashcode2021-can-i-change-this”这个项目时,很...
HashMap是一个基于哈希表实现的键值对存储结构,它提供了快速的插入、删除和查找操作,平均时间复杂度为O(1)。HashMap非线程安全,适合于单线程环境或已经通过并发工具类控制并发的场景。 二、HashMap底层原理 ...
【标题】"第一行代码Java源代码第13章课程代码Java类集框架"涉及到的是Java编程中的核心概念——类集框架。这个标题表明我们将会深入学习Java编程中关于类库和集合的重要部分,这是Java应用程序开发的基础。"第一行...
从实现上来说,java是借助hashcode()方法和equals()方法来实现判断元素是否已经存在的。当我们向HashMap中插入元素A时,首先,调用hashcode()方法,判断元素A在容器中是否已经存在。如果A元素的hashcode值在HashMap...