HashMap底层原理

哈希表基础

哈希表是一个数组形式的数据结构,其中每个元素被称为桶(bucket)。每个桶可以包含多个键值对。为了确定一个键值对应该存储在哪个桶中,需要使用哈希函数(hash function)来计算键的哈希码(hash code)。

工作流程

  1. 计算哈希码: 当你向 HashMap 添加一个键值对时,首先会计算键的哈希码。这是通过调用键对象的 hashCode() 方法完成的。

  2. 确定索引位置: 计算得到的哈希码经过一定的算法转换成桶的索引位置(index)。索引计算公式通常是 index = hash % table.length,其中 table.length 是桶数组的长度。

  3. 解决碰撞: 如果多个键值对的哈希码计算出来的索引相同,则会发生碰撞。HashMap 使用链表或者红黑树来解决碰撞问题:

    • 在 Java 8 及之前版本中,如果多个键值对的哈希码相同,它们会被链接到同一个桶中的链表上。
    • 从 Java 8 开始,当链表中的节点数量达到一定阈值时(默认为 8),链表会被转化为红黑树,以提高查找效率。当树中的节点数量低于另一个阈值(默认为 6)时,红黑树又会退化回链表。
  4. 存储键值对: 键值对被存储在指定桶的链表或红黑树中。每个键值对以 Node 形式存储,其中包含键、值、哈希码和指向下一个节点的引用。

  5. 查找键值对: 当你通过键查询值时,HashMap 会再次计算键的哈希码,并使用相同的索引计算公式找到桶的位置。然后遍历该桶中的链表或红黑树,使用 equals() 方法来判断键是否匹配。

扩容机制

随着键值对的增多,哈希表可能会变得拥挤,这会导致更多的碰撞和降低性能。为了保持性能,HashMap 在桶数组达到一定的负载因子(load factor)时会自动扩容。负载因子是桶数组的大小和已存储的键值对数量之间的比率,默认为 0.75。这意味着当已存储的键值对数量超过数组长度的 75% 时,HashMap 将会扩容。

扩容过程中,旧的桶数组会被废弃,创建一个新的更大的桶数组,并将所有键值对重新哈希到新的数组中。这个过程称为“rehashing”。

小练习:

1.将省份和城市的名称保存在集合中,当用户选择省份以后,二级联动,显示对应省份的地级市供用户选择。

效果演示:

class CityMap{
	
	public static Map model = new HashMap();
	
	static {
		model.put("北京", new String[] {"北京"});
		model.put("上海", new String[] {"上海"});
		model.put("天津", new String[] {"天津"});
		model.put("重庆", new String[] {"重庆"});
		model.put("黑龙江", new String[] {"哈尔滨","齐齐哈尔","牡丹江","大庆","伊春","双鸭山","绥化"});
		model.put("吉林", new String[] {"长春","延边","吉林","白山","白城","四平","松原"});
		model.put("河北", new String[] {"石家庄","张家口","邯郸","邢台","唐山","保定","秦皇岛"});
	}
}

public class ProvinceTest {
	public static void main(String[] args) {
		
		Set keySet = CityMap.model.keySet();
		for(Object s : keySet) {
			System.out.print(s + "\t");
		}
		System.out.println();
		System.out.println("请选择你所在的省份:");
		Scanner scan = new Scanner(System.in);
		String province = scan.next();
		
		String[] citys = (String[])CityMap.model.get(province);
		for(String city : citys) {
			System.out.print(city + "\t");
		}
		System.out.println();
		System.out.println("请选择你所在的城市:");
		String city = scan.next();
		
		System.out.println("信息登记完毕");
	}
	
}
2.统计字符串中每个字符出现的次数

String str = "aaaabbbcccccccccc";

提示:

char[] arr = str.toCharArray(); //将字符串转换成字符数组

HashMap hm = new HashMap(); //创建双列集合存储键和值,键放字符,值放次数

public class WordCountTest {
	public static void main(String[] args) {
        String str = "aaaabbbcccccccccc";
        char[] arr = str.toCharArray(); // 将字符串转换成字符数组
        HashMap map = new HashMap(); // 创建双列集合存储键和值

        for (char c : arr) { // 遍历字符数组
            if (!map.containsKey(c)) { // 如果不包含这个键
                map.put(c, 1); // 就将键和值为1添加
            } else { // 如果包含这个键
                map.put(c, (int)map.get(c) + 1); // 就将键和值再加1添加进来
            }

        }

        for (Object key : map.keySet()) { // 遍历双列集合
            System.out.println(key + "=" + map.get(key));
        }

    }
}
  • 5
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值