侧边栏壁纸
博主头像
霖祥的小破站博主等级

欢迎来到霖祥的小破站,这里是一个汇聚编程者共同探索、分享和成长的地方。我们致力于为广大程序员提供最新的编程技术动态、深度的技术文章和实用的开发经验。无论你是前端开发、后端工程师、数据科学家还是人工智能研究者,这里都将是你不可或缺的技术指南。 在霖祥的小破站,你将发现: 热门编程语言与框架的深度解读与比较,助你选择最适合的工具。 实用的编码技巧与项目经验分享,让你的代码更加优雅高效。 最新科技趋势与前沿技术的解析,助你把握行业发展脉搏。 共享精彩项目案例,启发你的创造力与思维方式。 加入我们,一起踏上无尽可能的编程之路,让技术之花在你手中绽放!

  • 累计撰写 12 篇文章
  • 累计创建 8 个标签
  • 累计收到 14 条评论

目 录CONTENT

文章目录

java基础-集合

霖祥的小破站
2024-06-20 / 3 评论 / 3 点赞 / 450 阅读 / 2,356 字

视频链接:https://www.bilibili.com/video/BV1fG4y1g76v?p=5&vd_source=d895293f5f20ef79bd6ffbeb4865aae9

1. 集合

collection和map分别为单列集合的祖宗和双列集合(一次性插入)的祖宗。list和set通过实现collection使用。

collection

image-1718876464929

1. 数据结构

数组:连续的地址空间,通过下标快速查找,删除和添加需要移动数组元素所以慢。

image-1718876470398

链表:不连续的地址空间,通过指针指向前一个和后一个。删除和插入只需要通过去掉指针和移动指针指向即可。查询比较慢因为每次查询都需要从头开始遍历。

image-1718876476180

  • 集合看名字知道数据结构并了解数据结构特点。
    image-1718876483389

树:一个节点之间不仅仅存储值,还存储左右父节点地址(父左右节点存在时)

image-1718876487957

小结:

image-1718876494068

1. 什么是二叉树?

  • 一种存储数据的数据结构,特点是每个节点最多两个子节点。每个节点的值是无规律的。

2. 二叉查找树?

  • 特点是:最多两个子节点。任何节点的左子节点比该节点小,任何右子节点比此节点大。
    image-1718876515226

3. 什么是平衡二叉树?

  • 任意节点左右子树的高度差不超过1。
    image-1718876520425
  • 如何保证平衡的?
    • 通过旋转机制达到平衡。
    • 类别包含左旋和右旋。
    • 旋转触发是由插入新数据时,破坏了平衡就会旋转。
  • 如何旋转?
    • 左旋:图一为简单的左旋结构,需要旋转的根节点上无多余的节点。
      image-1718876525501
      • 较为复杂的左旋:需要将9这个节点作为降级的根节点7的右子节点。
        image-1718876530049
    • 右旋:同理简单和复杂的类似左旋
      image-1718876534404
  1. 红黑树
  • 由于平衡二叉树每次节点的左右节点高度差超过1就要自旋调整。所以引入红黑树。红黑树不是高度平衡的,通过红黑规则进行实现。
  • 红黑树增删查改效率都很高。
  • 红黑树增加节点的时候,默认是红色的。因为红色效率高,调整红黑颜色次数较少。
    image-1718876540110

2. list 有序可重复有索引

ArrayList数据结构和扩容机制

  • 底层是数组结构,初始化长度为0,当插入第一个数据的时候默长度为10,满之后扩展到1.5倍。当一次插入多个则以实际长度扩容。
    image-1718876545535

LinKedList数据接口和扩容机制

  • 底层是双向链表 头节点数据和尾节点。
  • add数据过程为:重点是头节点和尾节点,每次记录上个节点的地址记录到下一个地址的头部。
    image-1718876550479

CopyOnWriteArrayList

  • CopyOnWriteArrayList是什么?
    • 相当于线程安全的arrayList
  • 实现原理?
    • 当写入数据时,先拷贝一份数组,然后对新数组进行操作,之后将引用指向新数组,注意add操作期间都是加锁的(sysnconized),所以能保证线程安全。这样做的好处是并发读取时不会加锁,提高读取效率。所以适合读多写少的场景。
    • 缺点就是:复制数组开销大。

3. set

hashSet 无序不可重复

  • 元素是唯一的,重复添加数据时,会返回false
    image-1718876561155
  • 由于set和list都是继承collection,所以增删改查方法基本一样哦。
  • hashSet底层是通过哈希表实现的。
    • 哈希表由jdk8之前由数组+链表组成,jdk8之后由数组+链表+红黑树组成。
    • 什么是hashcode?hashcode是对象的整数值表达式
      • hashcode默认是根据 对象.hashcode() 方法计算出的。本质是对象的内存地址经过转换的出的整数值。
        image-1718876567223
        image-1718876571715
    • 当链表长度大于8且数组长度大于等于64的时候,链表就会转换为红黑树。
    • 回答下列三个问题:
      • 1.因为存的时候如果相同hashcode不同属性值的是存放在链表中,而取得话是根据依次或者数组和数组下的链表,所以顺序不一致。
      • 2.数据结构多没有好的方式定义索引。
      • 3.利用hashcode和equles方法比较。
        image-1718876578674
        image-1718876583151

treeSet 可排序 不可重复

  • 底层是基于红黑树实现的
  • 可排序:如果是基本类型则输出set后会按照数字大小升序排列(1,2,3,4),如果是引用类型则按照ascii进行排序输出(a,b,c,d)
  • 默认使用treeset需要实现comprable接口,重写里面的compareTo方法指定字段继续比较排序。
    • treeset实现比较的方式有两种:
      • 实现comprable接口,重写里面的compareTo方法
        image-1718876589344
      • New comparator()重写里面的compare方法,先进行字段排序,之后在调用compareto方法比较。
        image-1718876594184
        image-1718876599560
        image-1718876604507
        image-1718876609832

linkedHashSet 有序不可重复

  • 1.底层数据结果依旧是哈希表,不同的是多了一个双向链表用来记录存入的元素顺序。
  • 2.读取数据的时候就不再是按照数组下标遍历了,而是遍历双向链表依次获取元素。
    image-1718876615260

ConcurrentHashMap 线程安全

如何实现的呢?

  • jdk1.7之前采用分段锁,使用ReentrantLock实现。jdk1.8之后采用cas+synchronized锁桶下标。

重写hashcode和equals方法

  • 重写的目的是将hashcode默认的地址转换的整数值变成由对象属性值相同hashcode就相同。
  • 比较的是对象的引用也就是地址值是否相等。equals一般跟都是比较地址值,但大多数都会重写equals方法比较属性值。

4. map

hashmap 集合&HashMap

  • hashmap底层结构跟hashset是一样的都是哈希表。
  • hashmap存储数据的过程:
    • 1.跟value没关系!调用object的hashcode方法计算key的hashcode,然后取高低16位进行异或计算,在与数组进行&运算最后找到桶的位置。
    • 2.然后比较桶中的key是否为空,空则存储。不为空则比较是否相等,相等则替换value值,不等则存储在链表中。(与hashset最大的区别在于hashset如果equals相同则不存,而hashmap多了一个value,所以会替换相同key 的value值)
      image-1718876622493

hash冲突?

  • 什么是hash冲突?
    • 不同对象计算出的hashcode值相同,存储在同一个桶位置时就会冲突。
  • hash解决冲突的方式?
    • 1.拉链法 hashmap采用的方式 也就是相同hashcode不同属性值通过尾插法保存到链表上。jdk8之前使用头插法
    • 2.再hash法 如果冲突则还另一种hash算法计算
    • 3.开放定址法 冲突时找一个空闲的数组进行存储即可。
  • hashmap采用的方式 拉链法
  • hashmap的线程安全?
    • 线程不安全,可以使用ConcurrentHashMap实现高并发的场景

hashmap的扩容?

  • hashmap的扩容机制:初始化数组长度时16,负载因子7.5 当存储的数据达到12时进行扩容两倍。当链表长度达到8且数组长度64时链表转换为红黑树。如果继续扩容当链表小于6时又会转换为链表。

Hashtable 线程安全

  • 底层都是数组加链表 注意初始值长度为11 每次扩容为2倍加1
  • 为什么线程安全,因为hashtable的所有方法都加了synchronized,所有线程调用方法都要依次排队。
  • hashtable的key和value是不能为空的,否则报空指针。
    image-1718876630905

面试常问

自测题:1. java集合自测题(高阶源码版)
2. https://www.yuque.com/hollis666/wty0im/gxi0rc

1. 线程安全的集合有哪些?concurrentHashMap hashtable copyOnWriteArrayList

2. 了解过fail-fast和fail-safe吗? 待理解

3. 除了自带的线程安全集合,如何将集合变成线程安全的呢?

  • 1.使用synchronized或者ReentrantLock对代码加锁(读写都要加锁)
    image-1718876639029
  • 2.使用Collections.synchronizedList/map(new arrayList<>/new hashMap())获取线程安全的集合。
    image-1718876643900

4. hashmap中为什么长度达到8才转红黑树呢?

  • 1.如果使用红黑树替换链表,是因为红黑树的空间大小是链表的两倍,比较浪费空间。
  • 2.前提是红黑树的查询速度是比链表快的,但是插入数据上效率要慢得多。所以当hash冲突导致链表长度到达8时(达到8的概率极低统计学计算得出)使用红黑树兜底提供查询效率。
  • 3.为什么是6是转换为链表,而不是小于8就转。防止频繁在链表和红黑树之间的转换。

5.扩容机制有了解吗?

3

评论区