HashMap主要是用数组来存储数据的.数组存储的是链表,链表是为了解决哈希冲突的.
几个关键的属性
存储数据的数组
transient Entry[] table; 这个上面已经讲到了
默认容量
static final int DEFAULT_INITIAL_CAPACITY = 16;
最大容量
static final int MAXIMUM_CAPACITY = 1 =容量*加载因子时,HashMap会将容量扩容
static final float DEFAULT_LOAD_FACTOR = 0.75f;
当实际数据大小超过threshold时,HashMap会将容量扩容,threshold=容量*加载因子 默认为12
int threshold;
加载因子
final float loadFactor;
HashMap的初始过程
构造函数1
Java代码
public HashMap(int initialCapacity, float loadFactor) {
if (initialCapacity MAXIMUM_CAPACITY)
initialCapacity = MAXIMUM_CAPACITY;
if (loadFactor = initialCapacity
int capacity = 1;
while (capacity >> 14);
h += (h >> 10);
return h;
}
private static int newHash(int h) {
// This function ensures that hashCodes that differ only by
// constant multiples at each bit position have a bounded
// number of collisions (approximately 8 at default load factor).
h ^= (h >>> 20) ^ (h >>> 12);
return h ^ (h >>> 7) ^ (h >>> 4);
}
其实HashMap的哈希函数会一直都是oldHash。
如何扩容?
当put一个元素时,如果达到了容量限制,HashMap就会扩容,新的容量永远是原来的2倍。
上面的put方法里有这样的一段:
Java代码
if (size++ >= threshold)
resize(2 * table.length);
这是扩容判断,要注意,并不是数据尺寸达到HashMap的最大容量时才扩容,而是达到 threshold指定的值时就开始扩容, threshold=最大容量*加载因子。 看看resize方法
Java代码
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);
}
重点看看红色部分的 transfer方法
Java代码
void transfer(Entry[] newTable) {
Entry[] src = table;
int newCapacity = newTable.length;
for (int j = 0; j e = src[j];
if (e != null) {
src[j] = null;
do {
Entry<k> next = e.next;
int i = indexFor(e.hash, newCapacity);
e.next = newTable[i];
newTable[i] = e;
e = next;
} while (e != null);
}
}
}
tranfer方法将所有的元素重新哈希,因为新的容量变大,所以每个元素的哈希值和位置都是不一样的。
一开始要估计好容量的大小 否则等到自动扩充的时候要将所有元素的hash重算一遍,照成浪费。
总结:应该制衡时间与空间。</k>
分享到:
相关推荐
本文将详细介绍如何对HashMap进行排序以及相关的知识点。 **1. HashMap的特点** HashMap的核心特点是其内部通过哈希函数来计算元素的存储位置,这使得查找、插入和删除操作的时间复杂度在平均情况下为O(1)。然而,...
在使用HashMap时,需要注意以下几点: - 自定义键类时,确保正确实现equals()和hashCode()方法,以确保对象的比较逻辑和哈希计算一致。 - 选择合适的初始容量(initialCapacity)和负载因子,以优化HashMap的性能。...
总结来说,HashMap 提供了快速的键值对存储和查找,但在遍历操作中需要注意效率。选择数据结构时,应考虑是否需要线程安全、是否频繁插入/删除、以及访问模式等因素。在多线程环境下,若需保证线程安全,可以考虑...
但需要注意的是,只能有一个键为`null`的映射关系;可以有多个值为`null`的映射关系。 #### 三、性能差异 - **HashTable**: 由于其内部采用了同步机制,因此在多线程环境下表现更加稳定可靠。但是,这种同步也带来...
但是需要注意,虽然这个方法可以保证基本的线程安全,但迭代仍然是非线程安全的,即不能在遍历过程中修改Map。 2. 使用ConcurrentHashMap:Java从1.5版本开始引入了ConcurrentHashMap,它是线程安全且高并发性能的...
值得注意的是,由于HashMap的Entry数组是动态扩容的,数组的长度会根据实际存储的键值对数量进行增长,以保持较低的哈希冲突率。但是,在数组扩容时,所有的键值对都需要重新计算哈希值并分配到新的位置,这个过程...
在JavaScript中,HashMap是一种数据结构,它存储键值对,并且通过键来快速查找值。虽然JavaScript原生的`Map`对象提供了类似的功能,但在某些场景下,开发者可能需要自定义HashMap来满足特定的需求,例如优化性能...
哈希映射(HashMap)是Java编程语言中一...此外,还需注意内存占用,因为HashMap会存储键值对的引用,如果键或值是大对象,可能会导致内存消耗过大。因此,合理选择数据结构以及正确使用HashMap是优化程序性能的关键。
为了提高性能,我们需要注意以下几点: 1. 初始化容量:预估ArrayList或HashMap的大小并设置初始容量,可以减少扩容操作。 2. 使用合适的泛型类型:明确指定ArrayList和HashMap中存储的对象类型,可以避免类型转换...
HashMap是Java编程语言中的一种重要数据结构,它在Android开发中同样被广泛...为了进一步提高效率和避免内存泄漏,要注意合理设置HashMap的初始容量和加载因子,以及在不再需要时及时清理HashMap引用,避免内存泄漏。
HashMap是Java语言中非常常见的一种数据结构,主要用于存储键值对。...请注意,由于文档内容是OCR扫描后的文字,存在个别字词识别错误或遗漏,但是通过上下文和已有知识,我们能够理解其意义并进行分析。
在使用`Iterator`时,要注意不要在遍历过程中修改`HashMap`,因为这可能会抛出`ConcurrentModificationException`。如果必须修改,可以使用`Iterator`的`remove()`方法,或者使用Java 8引入的流(Stream)API,这样...
但需要注意的是,如果键或值是对象引用,记得正确管理它们的生命周期,以免出现悬挂引用。 5. **线程安全:** - 默认情况下,Delphi的TDictionary不是线程安全的,如果你在多线程环境中使用,需要自己实现同步机制...
在实际编程中,我们需要注意HashMap的一些限制和陷阱,比如键的哈希函数质量直接影响HashMap的性能,以及null键和值的特殊处理。此外,当多个线程同时修改HashMap时,如果不进行同步控制,可能会导致数据不一致的...
这里需要注意的是,`#{status}` 表示参数占位符,会被实际传入的值替换。`resultClass` 设置为 `"java.util.HashMap"` 表示查询结果将以 `HashMap` 形式返回。 #### 4. Dao 层实现 接下来,在 Dao 层实现类中,...
注意,由于JNI操作不自动管理内存,所以在完成操作后,必须确保正确地释放任何分配的资源。 对于其他类型的对象,如自定义类实例,你需要为它们定义Java层的本地方法签名,然后在C/C++代码中使用`FindClass`找到...
通过这样的方式,我们可以实现对HashMap值的排序,但请注意,这并不改变原HashMap的结构,只是生成了一个排序后的视图。如果需要在HashMap中直接排序,可能需要结合其他数据结构如TreeMap或LinkedHashMap。如果想...
需要注意的是,如果有多个键对应同一个值,此方法会返回一个包含所有这些键的列表。在示例中,键"3"和"4"都与值"c"相对应,所以输出结果为["3", "4"]。 总结来说,这段代码展示了如何在HashMap中通过值来查找键,这...
在使用HashMap时,需要注意以下几点: 1. 自定义键类需重写equals()和hashCode()方法:为了确保HashMap能够正确地处理键值对,自定义键类需要重写equals()和hashCode()方法,确保它们遵循等价关系原则,即两个相等的...