阿里云Java中级面试记录整理 本文档主要讨论了 Java 中的 Collection 框架,特别是 List 和 Set 的区别、HashSet 的实现机制、HashMap 的线程安全性问题、扩容机制等。 List 和 Set 的区别: List 和 Set 都是继承自 Collection 接口,但是它们有着不同的特点。List 的元素有放入顺序,元素可重复,而 Set 的元素无放入顺序,元素不可重复,重复元素会覆盖掉。Set 的元素虽然无放入顺序,但是元素在 Set 中的位置是有该元素的 HashCode 决定的,其位置其实是固定的。加入 Set 的 Object 必须定义 equals() 方法。List 支持 for 循环,也就是通过下标来遍历,也可以用迭代器,但是 Set 只能用迭代器,因为它无序,无法用下标来取得想要的值。 HashSet 的实现机制: HashSet 是如何保证不重复的?向 HashSet 中 add() 元素时,判断元素是否存在的依据,不仅要比较 hash 值,同时还要结合 equals() 方法比较。HashSet 中的 add() 方法会使用 HashMap 的 add() 方法。HashMap 的 key 是唯一的,由上面的代码可以看出 HashSet 添加进去的值就是作为 HashMap 的 key。所以不会重复(HashMap 比较 key 是否相等是先比较 hashcode 在比较 equals)。 HashMap 的线程安全性问题: HashMap 不是线程安全的。如果有两个线程 A 和 B,都进行插入数据,刚好这两条不同的数据经过哈希计算后得到的哈希码是一样的,且该位置还没有其他的数据。所以这两个线程都会进入我在上面标记为 1 的代码中。假设一种情况,线程 A 通过 if 判断,该位置没有哈希冲突,进入了 if 语句,还没有进行数据插入,这时候 CPU 就把资源让给了线程 B,线程 A 停在了 if 语句里面,线程 B 判断该位置没有哈希冲突(线程 A 的数据还没插入),也进入了 if 语句,线程 B 执行完后,轮到线程 A 执行,现在线程 A 直接在该位置插入而不用再判断。这时候,你会发现线程 A 把线程 B 插入的数据给覆盖了。发生了线程不安全情况。 HashMap 的扩容机制: HashMap 的扩容过程是当向容器添加元素的时候,会判断当前容器的元素个数,如果大于等于阈值(即当前数组的长度乘以加载因子的值)的时候,就要自动扩容啦。扩容(resize)就是重新计算容量,向 HashMap 对象里不停的添加元素,而 HashMap 对象内部的数组无法装载更多的元素时,对象就需要扩大数组的长度,以便能装入更多的元素。 HashMap 1.7 与 1.8 的区别: HashMap 在 JDK1.7 及之前的版本中,又叫散列链表:基于一个数组以及多个链表的实现,hash 值冲突的时候,就将对应节点以链表的形式存储。JDK1.8 中,当同一个 hash 值(Table 上元素)的链表节点数不小于 8 时,将不再以单链表的形式,而是使用红黑树来存储节点。这使得 HashMap 的查询和插入效率都得到了提高。 本文档总结了 Java 中 Collection 框架的重要知识点,包括 List 和 Set 的区别、HashSet 的实现机制、HashMap 的线程安全性问题、扩容机制等。
剩余12页未读,继续阅读
- 粉丝: 1786
- 资源: 320
- 我的内容管理 展开
- 我的资源 快来上传第一个资源
- 我的收益 登录查看自己的收益
- 我的积分 登录查看自己的积分
- 我的C币 登录后查看C币余额
- 我的收藏
- 我的下载
- 下载帮助
评论0