HashMap

本文详细介绍了Java中的Map接口及其实现类HashMap的工作原理。HashMap的特点包括无序、键不可重复,允许使用null键值。它使用数组+链表/红黑树的数据结构,当链表长度达到8且数组长度大于64时,会转换为红黑树以提高查找效率。HashMap还涉及到关键参数如初始容量和加载因子,以及扩容策略。此外,文章还提到了Collections工具类的一些常用方法,如反转、随机排序和排序集合。
摘要由CSDN通过智能技术生成

Map体系集合

  • Map接口的特点:
    • 用于存储任意键值对(Key-Value)。
    • 键:无序、无下标、不允许重复
    • 值:无序、无下标、允许重复

Map集合概述

  • 特点:存储一对数据(Key-Value),无序、无下标,键不可重复。
  • 方法
    • V put(K key,V value)//将对象存入到集合中,关联键值。key重复则覆盖原值。
  • Object get(Object key)//根据键获取相应的值。
    • Set<K>//返回所有的key
    • Collection<V> values()//返回包含所有值的Collection集合。
    • Set<Map.Entry<K,V>>//键值匹配的set集合
/**
 * Map接口的使用
 * 特点:1.存储键值对 2.键不能重复,值可以重复 3.无序
 */
public class Demo1 {
	public static void main(String[] args) {
		Map<String,Integer> map=new HashMap<String, Integer>();
		//1.添加元素
		map.put("tang", 21);
		map.put("he", 22);
		map.put("fan", 23);
		System.out.println(map.toString());
		//2.删除元素
		map.remove("he");
		System.out.println(map.toString());
		//3.遍历
		//3.1 使用keySet();
		for (String key : map.keySet()) {
			System.out.println(key+" "+map.get(key));
		}
		//3.2 使用entrySet();效率较高
		for (Map.Entry<String, Integer> entry : map.entrySet()) {
			System.out.println(entry.getKey()+" "+entry.getValue());
		}
	}
}

Map集合的实现类

HashMap【重点】
  • 线程不安全,运行效率快;允许用null作为key或是value

1.HashMap的节点

static class Node<K,V> implements Map.Entry<K,V> {
   final int hash;
   final K key;
   V value;
   Node<K,V> next;

Node是一个内部类,这里的key为键,value为值,next指向下一个元素,可以看出HashMap中的元素不是一个单纯的键值对,还包含下一个元素的引用。

2.HashMap的数据结构:

HashMap的数据结构为数组+(链表或红黑树)

数组的特点:查询效率高,插入,删除效率低。

链表的特点:查询效率低,插入删除效率高。

在HashMap底层使用数组加(链表或红黑树)的结构完美的解决了数组和链表的问题,使得查询和插入,删除的效率都很高。

3.HashMap存储元素的过程

Map<String,String> map = new HashMap<String,String>();
map.put("小明","团员");
map.put("小龙","党员");
  1. 先计算“小明”的hashcode,该值用来定位将这个元素存放到数组中的什么位置

哈希码的特点:

  • 对于同一个对象如果没有被修改(使用equals比较返回true),那么无论何时它的hashcode

    值都是相同的。

  • 对于两个对象如果他们的equals返回false,那么他们的hashcode值也有可能相等

​ 明白了hashcode我们再来看元素如何通过hashcode定位到要存储在数组的哪里,通过hashcode值和数组长度取模我们可以得到元素存储的下标。

例子

小明的hashcode为756703 数组长度为 16则要存储在数组索引为 20977295%16=1的地方

可以分两种情况:

  1. 数组索引为1的地方是空的,这种情况很简单,直接将元素放进去就好了。

  2. 已经有元素占据了索引为1的位置,这种情况下我们需要判断一下该位置的元素和当前元素是否相等,使用equals来比较。

​ 如果使用默认的规则是比较两个对象的地址。也就是两者需要是同一个对象才相等,当然我们也可以重写equals方法来实现我们自己的比较规则最常见的是通过比较属性值来判断是否相等。

​ 如果两者相等则直接覆盖,如果不等则在原元素下面使用链表的结构存储该元素每个元素节点都有一个next属性指向下一个节点,这里由数组结构变成了数组+链表结构,红黑树又是怎么回事呢?

​ 因为链表中元素太多的时候会影响查找效率,所以当链表的元素个数达到8的时候使用链表存储就转变成了使用红黑树存储,原因就是红黑树是平衡二叉树,在查找性能方面比链表要高.

4、HashMap中的两个重要的参数

  • 初始容量大小 默认值为16
  • 加载因子 默认值0.75f

用数组容量大小乘以加载因子得到一个值,一旦数组中存储的元素个数超过该值就会调用rehash方法将数组容量增加到原来的两倍,专业术语叫扩容

在做扩容的时候会生成一个新的数组,原来的所有数据需要重新计算哈希码值重新分配到新的数组,所以扩容的操作非常消耗性能.

5、java 1.7 和 java1.8 HashMap 的区别

jdk1.7中HashMap采用的是位桶+链表的方式,即我们常说的散列链表的方式,而

jdk1.8中采用的是位桶+链表/红黑树的方式,也是非线程安全的。当某个位桶的链表的长度达到某个阀值(8)的时候,这个链表就将转换成红黑树。

在jdk1.8中,如果链表长度大于8且节点数组长度大于64的时候,就把链表下所有的节点转为红黑树。

树形化还有一个要求就是数组长度必须大于等于64,否则继续采用扩容策略

总的来说,HashMap默认采用数组+单链表方式存储元素,当元素出现哈希冲突时,会存储到该位置的单链表中。但是单链表不会一直增加元素,当元素个数超过8个时,会尝试将单链表转化为红黑树存储。但是在转化前,会再判断一次当前数组的长度,只有数组长度大于64才处理。否则,进行扩容操作。

Collections工具类

  • 概念:集合工具类,定义了除了存取以外的集合常用方法。
  • 方法
    • public static void reverse(List<?> list)//反转集合中元素的顺序
    • public static void shuffle(List<?> list)//随机重置集合元素的顺序
    • public static void sort(List<T> list)//升序排序(元素类型必须实现Comparable接口)

参考博客
https://lazydog036.gitee.io/2020/10/29/JAVA%E9%9B%86%E5%90%88%E6%A1%86%E6%9E%B6/#Map%E9%9B%86%E5%90%88%E6%A6%82%E8%BF%B0[添加链接描述]

添加链接描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值