📖 day02 大纲
1️⃣ 重载与重写的区别
2️⃣ List 和 Set 区别
3️⃣ ArrayList 和 LinkedList 的区别
4️⃣ 谈一谈ConcurrentHashMap的扩容机制
5️⃣ 从 JDK 1.7 到 JDK 1.8 HashMap发生了什么变化(底层)
📑 重载与重写的区别
重载
发生在同一个类中,方法名必须相同,参数类型不同、个数不同、顺序不同,方法返回值和访问修饰符可以不用,发生在编译时。
重写
发生在父子类中,方法名、参数列表必须相同,返回值范围小于等于父类,抛出异常的范围小于等于父类,访问修饰符范围大于等于父类;如果父类方法访问修饰符为private 则子类就不能重写该方法。
public String add(int a , int b){
return "";
}
public int add(int a, int b){
return 0;
}
// 编译错误
📚 重载和返回值没有关系
📑 List 和 Set 的区别
List
List : 有序,按照对象进入的顺序保存对象,可重复,允许多个 Null 元素对象,可以使用迭代器(iterator)取出所有元素,在逐一遍历,还可以使用 get(int index)获取指定下表的元素。
Set
Set : 无序,不可重复,最多允许有一个Null元素对象,取元素时只能 用 iterator 取出所得所有元素,在逐一遍历各个元素
📑 ArrayList 和 LinkedList 的区别
1️⃣ 首先,他们的底层数据结构不同,ArrayList底层是基于 数组 实现的,LinkedList 底层是基于链表实现的。
2️⃣ 由于底层数据结构不同,他们所适用的 场景也是不同,ArrayList 更适合随机查找,LinkedList 更适合删除和添加,查询、添加、删除的时间复杂度不同。
3️⃣ 另外 ArrayList 和 LinkedList 都实现了 List 接口 ,但是 LinkedList 还额外实现了Deque接口,所以 LinkedList 还可以当做队列来使用。
📑 谈一谈ConcurrentHashMap的扩容机制
JDK 1.7
1️⃣ 1.7 版本的 ConcurrentHashMap 是基于Segment 分段实现的
2️⃣ 每个 Segment相对于一个小型的 HashMap
3️⃣ 每个 Segment 内部会进行扩容 和 HashMap 的扩容逻辑类似
4️⃣ 先生成新的数组,然后转移元素到新的数组中
5️⃣ 扩容的判断也是每个 Segment 内部单独判断的,判断是否超过阈值
JDK 1.8
1️⃣ 1.8 版本的 ConcurrentHashMap 不再基于 Segment 实现
2️⃣ 当某个线程 进行 put 时,如果发现 ConcurrentHashMap 正在进行扩容,那么该线程一起进行扩容。
3️⃣ 如果某个线程 put 时,发现没有正在进行扩容,则将 key-value 添加到 ConcurrentHashMap 中,然后判断是否超过了 阈值,超过了则进行扩容。
4️⃣ ConcurrentHashMap 是支持多个线程同时扩容的
5️⃣ 扩容之前也会先生成一个新的数组
6️⃣ 在转移元素时,先将原数组分组,将每组分给不同的线程来进行元素的转移,每个线程负责一组或多组的元素转移工作。
📑 从 JDK 1.7 到 JDK 1.8 HashMap发生了什么变化(底层)
1️⃣ 1.7 中底层是 数组 + 链表 而 1.8 中底层是 数组 + 链表 + 红黑树 ,加红黑树的目的是提高 HashMap 的插入和查询的整体效率。
2️⃣ 1.7 中链表 插入使用的是 头插法,1.8中链表使用的是尾插法,因为 1.8 中插入key 和 value时需要判断链表元素个数,所以需要遍历链表统计链表元素个数,所以就直接采用尾插法。—— 不严谨 —— 看上面的链接中详解。可能会出现 Infinite Loop
3️⃣ 1.7 中哈希算法比较复杂,存在各种右移与异或运算,1.8中进行了简化,因为复杂的哈希算法的目的就是提高散列性,来提供HashMap的整体效率,而 1.8 中新增了红黑树,所以可以适当的简化 哈希算法,节省 cpu 资源