1. Collection集合几种遍历

1.1 迭代器遍历

  • 迭代器是用来遍历集合的专用方式(数组没有迭代器),在 Java 中迭代器的代表是Iterator

迭代器

  • 获取集合的迭代器
Iterator<E> iterator():得到迭代器对象,默认指向当前集合的索引0
  • 通过迭代器获取集合的元素,如果取元素越界会出现NoSuchElementException异常。

1.2 增强 for 循环遍历

  • 增强 for 可以用来遍历集合或者数组。
  • 增强 for 遍历集合,本质就是迭代器遍历集合的简化写法。
  • 格式:
for (元素的数据类型 变量名 : 数组或者集合){
}

1.3 Lambda 表达式

Lambda表达式遍历

1.4 三种遍历方式的区别

解决并发修改异常问题的方案:

  • 如果集合支持索引,可以使用 for 循环遍历,每删除数据后做 i--;或者可以倒着遍历。
  • 可以使用迭代器遍历,并用迭代器提供的删除方法删除数据。

注意: 增强 for 循环 / Lambda 遍历均不能解决并发修改异常问题,因此增它们只适合做数据的遍历,不适合同时做增删操作。

2. ArrayList 与 LinkedList 的底层原理

2.1 ArrayList底层是基于数组存储数据的。

  • 查询速度快(注意:是根据索引查询数据快):查询数据通过地址值和索引定位,查询任意数据耗时相同。
  • 增删数据效率低:可能需要把后面很多的数据进行前移。

2.2LinkedList底层是基于链表存储数据的。

  • 链表的特点1:查询慢,无论查询哪个数据都要从头开始找。
  • 链表的特点2:链表增删相对快。

3. HashSet集合的底层原理

  • 什么是哈希值?对象的哈希值有什么特点?
    对象调用 Object 的hashCode()方法得到的一个随机值。

  • HashSet 集合的底层原理是基于哈希表实现的

3.1 哈希值

  1. 哈希值就是一个int类型的随机值,Java 中每个对象都有一个哈希值。
  2. Java 中的所有对象,都可以调用 Obejct 类提供的 hashCode 方法,返回该对象自己的哈希值。
    public int hashCode():返回对象的哈希码值
  3. 对象哈希值的特点
  • 同一个对象多次调用hashCode()方法返回的哈希值是相同的。
  • 不同的对象,它们的哈希值大概率不相等,但也有可能会相等(哈希碰撞)。

3.2 哈希表

  1. JDK8 之前的哈希表:数组+链表

    • 创建一个默认长度 16 的数组,默认加载因子为 0.75,数组名 table 。
    • 使用元素的哈希值对数组的长度做运算计算出应存入的位置。
    • 判断当前位置是否为null,如果是null直接存入。
    • 如果不为null,表示有元素,则调用equals方法比较。
    • 相等,则不存;不相等,则存入数组。
  2. JDK8 开始的哈希表:数组+链表+红黑树

    • JDK8 开始,当链表长度超过 8,且数组长度 >= 64 时,自动将链表转成红黑树
  3. 区别

    • JDK8 之前,新元素存入数组,占老元素位置,老元素挂下面。
    • JDK8 开始之后,新元素直接挂在老元素下面。

3.3 HashSet集合元素的去重操作

  • 需求:创建一个存储学生对象的集合,存储多个学生对象,要求多个学生对象的成员变量值相同时,就认为是同一个对象,要求只保留一个。
  • 操作:
    1.定义学生类,创建HashSet集合对象,创建学生对象。
    2.把学生添加到集合。
    3.在学生类中重写两个方法,hashCode()equals(),自动生成即可。

4. LinkedHashSet 的底层原理

  1. 依然是基于哈希表(数组、链表、红黑树)实现的。
  2. 但是,它的每个元素都额外的多了一个双链表的机制记录它前后元素的位置。
  3. LinkedHashSet 集合的特点和原理:
    • 有序、不重复、无索引
    • 底层基于哈希表,使用双链表记录添加顺序。

5. TreeSet 集合

  • 特点:不重复、无索引、可排序(默认升序排序,按照元素的大小,由小到大排序)。
  • 底层是基于红黑树实现的排序。

注意:

  • 对于数值类型:IntegerDouble,默认按照数值本身的大小进行升序排序。
  • 对于字符串类型:默认按照首字符的编号升序排序。
  • 对于自定义类型如 Student 对象,TreeSet 默认是无法直接排序的。

5.1 自定义排序规则:

  • TreeSet 集合存储自定义类型的对象时,必须指定排序规则,支持如下两种方式来指定比较规则:
  1. 让自定义的类(如学生类)实现Comparable接口,重写里面的compareTo方法来指定比较规则。
  2. 通过调用TreeSet集合有参数构造器,可以设置Comparator对象(比较器对象,用于指定比较规则。
public TreeSet(Comparator<? super E> comparator)

两种方式中,关于返回值的规则:

  • 如果认为第一个元素 > 第二个元素 返回正整数即可。
  • 如果认为第一个元素 < 第二个元素返回负整数即可。
  • 如果认为第一个元素 = 第二个元素返回 0 即可,此时 Treeset 集合只会保留一个元素,认为两者重复。

注意:如果类本身有实现Comparable接口,TreeSet集合同时也自带比较器,默认使用集合自带的比较器排序。

5.2 TreeSet 集合的特点

  • 可排序、不重复、无索引
  • 底层基于红黑树实现排序,增删改查性能较好

5.3 TreeSet 合对自定义类型的对象排序,有几种方式指定比较规则?

  • 2种。
  • 类实现Comparable接口,重写比较规则。
  • 集合自定义Comparator比较器对象,重写比较规则。

6. 单列集合问题总结

  1. 希望记住元素的添加顺序,需要存储重复的元素,又要频繁的根据索引查询数据?
  • 用 ArrayList 集合(有序、可重复、有索引),底层基于数组的。(常用)
  1. 如果希望记住元素的添加顺序,且增删首尾数据的情况较多?
  • 用 LinkedList 集合(有序、可重复、有索引),底层基于双链表实现的。
  1. 如果不在意元素顺序,也没有重复元素需要存储,只希望增删改查都快?
  • 用 HashSet 集合(无序,不重复,无索引),底层基于哈希表实现的。(常用)
  1. 如果希望记住元素的添加顺序,也没有重复元素需要存储,且希望增删改查都快?
  • 用 LinkedHashSet 集合(有序,不重复,无索引),底层基于哈希表和双链表。
  1. 如果要对元素进行排序,也没有重复元素需要存储?且希望增删改查都快?
  • 用 TreeSet 集合,基于红黑树实现。

7. 双列集合

7.1 Map 集合

Map集合体系的特点

  • HashMap(由键决定特点):无序、不重复、无索引;(用的最多)
  • LinkedHashMap(由键决定特点):由键决定的特点:有序、不重复、无索引。
  • TreeMap(由键决定特点):按照大小默认升序排序、不重复、无索引。

注意:Map系列集合的特点都是由键决定的,值只是一个附属品,值是不做要求的

7.2 LinkedHashMap 的底层原理

  • 底层数据结构依然是基于哈希表实现的,只是每个键值对元素又额外的多了一个双链表的机制记录元素顺序(保证有序)。

实际上原来学习的LinkedHashSet集合的底层原理就是LinkedHashMap。

7.3 TreeMap 的使用

  • 特点:不重复、无索引、可排序(按照键的大小默认升序排序,只能对键排序)
  • 原理:TreeMap 跟 TreeSet 集合的底层原理是一样的,都是基于红黑树实现的排序。
  • TreeMap 集合同样也支持两种方式来指定排序规则。
  • 让类实现 comparable 接口,重写比较规则。
  • TreeMap 集合有一个有参数构造器,支持创建 Comparator 比较器对象,以便用来指定比较规则。

更多推荐