HashMap

本文详细介绍了HashMap在JDK1.7和1.8版本的区别,包括底层结构、插入方式、扩容策略的变化。1.7采用数组+链表,1.8引入了红黑树,头插法变为了尾插法,扩容策略也有所调整。同时,讨论了HashMap的扩容过程,以及HashMap与HashTable、TreeMap的异同,包括线程安全性、数据结构和操作效率等方面。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

关于面试常问HashMap的问题

1.jdk1.7和1.8HashMap有什么区别?
区别:
JDK1.7下:
1)底层所采用的是数组加链表的结构
2)采用头插法
3)扩容方式:直接用其hash值和需要扩容的二进制数进行&(这里的扩容时必须是2的幂次方,因为只有这样其二进制的最后一位才会是1,用来减少哈希冲突),(hash&table.length-1),另其是在插入后进行扩容
4)会先对数组进行初始化,然后进行put
jdk1.8:
1)底层采用的是数组+链表+红黑树,当链表长度大于8并且数组长度大于64时,会形成红黑树。
红黑树的特点:
每个节点只有两种颜色,红色或是黑色,根节点必须为黑
每个叶子结点都是黑色的空结点
从根结点到叶子结点时不能出现两个连续的红色结点
从任意结点出发,到它下边的子结点的路径包=包含的黑色结点数目相同
2)采用尾插法,原因是在JDK1.7时单链表进行的纵向延伸,当采用头插法时会容易出现逆序且环形链表死循环问题,而1.8下的尾插法可以解决这个问题
3)扩容方式:计算hash的方法yuJDK1.7有所不同,另其是在插入前进行扩容
4)会先进行put方法,如哦没有初始化,则在put方法内进行初始化

2.说说HashMap的扩容过程

HashMap只有在内部数组无法装载更多对象时,即size>threshold时需要对数组进行二倍扩容。
对原数组中的数据进行重新rehash。
rehash的结果,该值在原数组和新数组的位置相同或该值在新数组中的位置等于该值在原数组中的位置加上原数组的长度。

3.HashMap中可以使用自定义类型作为其key和value吗?
可以
如果是自定义的比较器时需要重写equals()方法和hashCode()方法。

4.HashMap与HashTable的区别和联系?
相同点:
都实现了Map接口,保存了Key-Value(键值对)
不同点:
1.HashMap继承AbstractMap类,而HashTable继承Dictionary类。
2.HashMap是线程不安全的,是非Synchronize(同步)的,而HashTable是线程安全的,是Synchronize的。
3.HashTable中key和value都不允许为null,HashMap中空值可以作为Key,也可以有一个/多个Key的值为空值。
4.HashMap的hash数组默认长度大小为16,扩容方式为2的指数,HashTable的hash数组默认长度大小为11,扩容方式为两倍加一。

5.HashMap与HashTable相同点和不同点
相同点:
都实现了Map接口,保存了Key-Value(键值对)
不同点:
1.HashMap继承AbstractMap类,而HashTable继承Dictionary类。
2.HashMap是线程不安全的,是非Synchronize(同步)的,而HashTable是线程安全的,是Synchronize的。
3.HashTable中key和value都不允许为null,HashMap中空值可以作为Key,也可以有一个/多个Key的值为空值。
4.HashMap的hash数组默认长度大小为16,扩容方式为2的指数,HashTable的hash数组默认长度大小为11,扩容方式为两倍加一。

  1. HashMap和TreeMap的相同点和不同点
    相同点:
    1)HashMap(JDK1.8下)和TreeMap都是基于数组加链表实现的
    2)HashMap和TreeMap都是非线程安全的
    不同点:
    1)HashMap继承于抽象类AbstractMap,并且实现Map接口,TreeMap实现SortedMap接口
    2)HashMap遍历时,取得的数据完全是随机的,TreeMap默认是按键值的升序排序,也可以指定排序的比较器,当用Iterator遍历TreeMap时,得到的记录是排过序的
    3)HashMap添加、删除操作时间复杂度都是O(1),TreeMap添加、删除操作时间复杂度都是O(log(n))
    4)HashMap最多只允许一条key为Null,允许多条value为Null,TreeMap只允许value为Null,key不能为Null

居中的图片: Alt
暂时想到就这么多,以后再补充吧

### 关于 `HashMap` 数据结构、用法及其实现详解 #### 定义与特性 `HashMap` 是基于哈希表的 `Map` 接口实现,主要用于存储键值对。该允许使用 `null` 作为键和值,并且是非线程安全的。默认情况下,`HashMap` 的初始容量为 16,在每次扩容时,容量会翻倍至原来的两倍,始终维持着数组长度为2的幂这一特点[^3]。 #### 使用方法 在 Java 中使用 `HashMap` 需要先导入相应的包: ```java import java.util.HashMap; ``` 创建并操作 `HashMap` 对象的例子如下所示: ```java // 创建一个新的 HashMap 实例 HashMap<String, Integer> map = new HashMap<>(); // 向 HashMap 添加元素 map.put("one", 1); map.put("two", 2); // 获取指定键对应的值 int valueOne = map.get("one"); // 移除某个键所映射的条目 map.remove("two"); ``` #### 底层数据结构解析 `HashMap` 内部维护了一个名为 `table` 的数组,用于保存实际的数据项。每当有新的键值对被加入时,程序会计算给定键对象的哈希码(`hash`),并通过 `(n - 1) & hash` 来决定新元素应该放置在哪一个桶(bucket)里;这里的 `n` 表示当前数组的实际大小。这种设计可以有效地减少冲突的发生几率,使得各个链表保持相对均衡的状态,从而提升查找性能[^4]。 为了确保上述逻辑能够正常工作,`HashMap` 要求内部使用的数组尺寸必须是2的整数次幂。这样做不仅简化了索引运算过程——即可以通过简单的位运算代替取模操作来获得目标位置——而且有助于更好地分布散列函数产生的不同哈希值,进一步优化访问速度。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值