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 复制代码
java.lang.Object
	java.util.AbstractMap<K,V>
		java.util.HashMap<K,V>
Type Parameters:
	K - the type of keys maintained by this map
	V - the type of mapped values
All Implemented Interfaces:
	Serializable, Cloneable, Map<K,V>
Direct Known Subclasses:
	LinkedHashMap, PrinterStateReasons

public class HashMap<K,V>
extends AbstractMap<K,V>
implements Map<K,V>, Cloneable, Serializable

基本类型与包装类

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

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

基本类型 引用类型
boolean Boolean
byte Byte
short Short
int Integer
long Long
float Float
double Double
char Character

常用实现

1、创建

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

2、添加元素 put() 方法:

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

java 复制代码
public class Test {
	public static void main(Strings[] args) {
		// 创建 HashMap 对象 A
		HashMap<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对象。

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

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

java 复制代码
public class Test{
	public static void main(String[] args) {
		// 创建 HashMap 对象 A
		HashMap<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() 方法.
java 复制代码
// 方法一:
      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).

java 复制代码
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).

java 复制代码
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.

java 复制代码
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.

java 复制代码
    public HashMap(Map<? extends K, ? extends V> m) {
        this.loadFactor = DEFAULT_LOAD_FACTOR;
        // 将m中的所有键值对添加到HashMap
        putMapEntries(m, false);
    }
java 复制代码
    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的基本用法

相关推荐
非著名架构师2 分钟前
js混淆的方式方法
开发语言·javascript·ecmascript
Themberfue3 分钟前
基础算法之双指针--Java实现(下)--LeetCode题解:有效三角形的个数-查找总价格为目标值的两个商品-三数之和-四数之和
java·开发语言·学习·算法·leetcode·双指针
AIGC破防黑吗喽4 分钟前
Midjourney零基础学习
人工智能·gpt·学习·ai·stable diffusion·midjourney·ai绘画
深山夕照深秋雨mo12 分钟前
在Java中操作Redis
java·开发语言·redis
努力的布布17 分钟前
SpringMVC源码-AbstractHandlerMethodMapping处理器映射器将@Controller修饰类方法存储到处理器映射器
java·后端·spring
xujinwei_gingko18 分钟前
Spring MVC 常用注解
java·spring·mvc
LearnTech_12318 分钟前
【学习笔记】手写一个简单的 Spring MVC
笔记·学习·spring·spring mvc
PacosonSWJTU22 分钟前
spring揭秘25-springmvc03-其他组件(文件上传+拦截器+处理器适配器+异常统一处理)
java·后端·springmvc
PacosonSWJTU24 分钟前
spring揭秘26-springmvc06-springmvc注解驱动的web应用
java·spring·springmvc
barbyQAQ30 分钟前
Qt源码阅读——事件循环
开发语言·数据库·qt