ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

HashMap学习

2026/8/16 18:35:32 拓冰建站 浏览量
HashMap学习

hashmap

  • 1、hashmap 与 hashtable 的区别
  • 2、hashmap
    • 基本类型与包装类
    • 常用实现
    • 变量介绍
      • HashMap的内部变量:
    • 初始容量和负载因子
    • 红黑树和链表转化
    • HashMap的内部数据结构
    • HashMap内部哈希算法
  • 参考文章

1、hashmap 与 hashtable 的区别

  1. 线程安全
  2. null值
  3. 执行效率

2、hashmap

hashmap是java中常用的集合类之一,

  1. 继承自AbstractMap类,实现了 Map、Cloneable、java.io.Serializable 接口。
  2. 使用哈希表来存储键值对(key-value),通过将键值映射成哈希码来进行高效的插入、删除操作。
  3. 具有很快的访问速度,最多允许一条记录的键为 null,不支持线程同步。
java.lang.Objectjava.util.AbstractMap<K,V>java.util.HashMap<K,V>
Type Parameters:K - the type of keys maintained by this mapV - the type of mapped values
All Implemented Interfaces:Serializable, Cloneable, Map<K,V>
Direct Known Subclasses:LinkedHashMap, PrinterStateReasonspublic class HashMap<K,V>
extends AbstractMap<K,V>
implements Map<K,V>, Cloneable, Serializable

基本类型与包装类

HashMap 中的元素实际上是对象,一些常见的基本类型可以使用它的包装类。

基本类型对应的包装类表如下:

基本类型引用类型
booleanBoolean
byteByte
shortShort
intInteger
longLong
floatFloat
doubleDouble
charCharacter

常用实现

1、创建

import java.util.HashMap; // 引入 HashMap 类
HashMap<Integer, String> A = new HashMap<Integer, String>();

2、添加元素 put() 方法:
当调用put方法的时候,先通过hashCode() 获取key 的hashCode,然后找到bucket位置,将Entry对象 存储到bucket上面。

public class Test {public static void main(Strings[] args) {// 创建 HashMap 对象 AHashMap<Integer, String> A = new HashMap<Integer, String>();// 添加键值对A.put(1, "apple");A.put(2, "banana");System.out.println(A);}
}

3、访问元素 get(key) 方法:
通过get(key)获取对象时,也是通过hashCode()方法 获取key的hashCode,然后得到Entry对象。

public class Test{public static void main(String[] args) {// 创建 HashMap 对象 AHashMap<Integer, String> A = new HashMap<Integer, String>();// 添加键值对A.put(1, "apple");A.put(2, "banana");// 访问System.out.println(A.get(1));}
}

4、删除元素 remove(key)方法:

public class Test{public static void main(String[] args) {// 创建 HashMap 对象 AHashMap<Integer, String> A = new HashMap<Integer, String>();// 添加键值对A.put(1, "apple");A.put(2, "banana");// 删除A.remove(1);}
}

5、删除所有元素 clear()方法

6、计算 HashMap 中元素的数量 size() 方法

7、 遍历

  1. 可以使用 for-each 来迭代 HashMap 中的元素
  2. 只想获得 key ,使用 KeySet() 方法,然后通过 get(key) 获取对应的 value
  3. 指向获得value,有getValue() 方法.
// 方法一:Iterator iterator = hashMap.keySet().iterator();while (iterator.hasNext()){String key = (String)iterator.next();System.out.println(key+"="+hashMap.get(key));}
// 方法二:Iterator iterator1 = hashMap.entrySet().iterator();while (iterator1.hasNext()){Map.Entry entry = (Map.Entry) iterator1.next();String key = (String) entry.getKey();Integer value = (Integer) entry.getValue();System.out.println(key+"="+value);}

变量介绍

该类提供了四种构造方法:
(1)HashMap()
Constructs an empty HashMap with the default initial capacity (16) and the default load factor (0.75).

public HashMap(){this.loadFactor = DEFAULT_LOAD_FACTOR; //all other fields defaulted
}

这是我们用的比较频繁的一个构造方法了,没有特殊的写法,所有变量均是默认值

(2) HashMap(int initialCapacity)
Constructs an empty HashMap with the specified initial capacity and the default load factor (0.75).

public HashMap(int initialCapacity) {this(initialCapacity, DEFAULT_LOAD_FACTOR);
}

该构造方法传入一个指定容量,然后调用另外一个重载的构造方法

(3) HashMap(int initialCapacity, float loadFactor)
Constructs an empty HashMap with the specified initial capacity and load factor.

public HashMap(int initialCapacity, float loadFactor) {if(initialCapacity < 0)throw new IllegalArgumentException("Illegal initial capacity: " +initialCapacity");if (initialCapacity > MAXIMUM_CAPACITY)initialCapacity = MAXIMUM_CAPACITY;if(loadFactor <= 0 || Float.isNaN(loadFactor))throw new IllegalArgumentException("Illegal load factor: " +loadFactor);this.loadFactor = loadFactor;this.threshold = tableSizeFor(initialCapacity);
}

该构造方法指定一个容量值和一个负载因子;从方法内部逻辑可以看出容量值小于0将会抛出异常,大于最大容量值就重置为最大值;负载因子 如果小于等于0或者是个非法数字也将会抛出异常;最后一句代码的意思是计算HashMap下次扩容时的阈值,也就是说HashMap并不会等被填满时才会进行扩容,而是达到这个阈值时就开始提前扩容

(4) HashMap(Map<? extends K,? extends V> m)
Constructs a new HashMap with the same mappings as the specified Map.

    public HashMap(Map<? extends K, ? extends V> m) {this.loadFactor = DEFAULT_LOAD_FACTOR;// 将m中的所有键值对添加到HashMapputMapEntries(m, false);}
    final void putMapEntries(Map<? extends K, ? extends V> m, boolean evict) {int s = m.size();if (s > 0) {if (table == null) { // pre-size//数组没有初始化 重新计算阈值float ft = ((float)s / loadFactor) + 1.0F;int t = ((ft < (float)MAXIMUM_CAPACITY) ?(int)ft : MAXIMUM_CAPACITY);if (t > threshold)threshold = tableSizeFor(t);}else if (s > threshold)//已经初始化 如果大小大于阈值 需要扩容resize();//将m中所有键值对添加到本HashMap中for (Map.Entry<? extends K, ? extends V> e : m.entrySet()) {K key = e.getKey();V value = e.getValue();putVal(hash(key), key, value, false, evict);}}}

HashMap的内部变量:

int DEFAULT_INITIAL_CAPACITY = 1 << 4

内部哈希表初始容量,值为16,值必须是2的幂次方

int MAXIMUM_CAPACITY = 1 << 30

哈希表最大容量,一般情况下只要内存够用,哈希表不会出现问题

float DEFAULT_LOAD_FACTOR = 0.75f

默认的负载因子,因此初始情况下,当键值对的数量大于 16 * 0.75 = 12 时,就会触发扩容

int TREEIFY_THRESHOLD = 8

这个值表示当某个桶中,链表长度大于 8 时,将链表转化成红黑树;如果哈希函数不合理,导致过多的数据碰撞,即使扩容也无法减少箱子中链表的长度,因此将链表转换成红黑树

int UNTREEIFY_THRESHOLD = 6:

当哈希表在扩容时,如果桶中的链表长度小于 6,则会由树重新退化为链表

int MIN_TREEIFY_CAPACITY = 64:

即哈希表中的桶数量要大于64才会考虑将链表转换成树,也是避免在小容量的时候进行不必要的转换

初始容量和负载因子

红黑树和链表转化

HashMap的内部数据结构

HashMap内部哈希算法

以上四节均学习于此文章:
源码解析-深刻理解Hash HashTable HashMap原理及数据hash碰撞问题

参考文章

官网描述
菜鸟教程
【深入Java基础】HashMap的基本用法