12 集合进阶(一)

目录

1、集合的体系结构

1.1 Collection

1.2 Collection的遍历方式

2、List集合

2.1 List简介

2.2 List集合特有的遍历方式:

2.3 List的实现类

2.3.1 ArrayList集合

2.3.2 LinkedList集合

3、泛型深入

3.1 泛型

3.2 泛型类

3.3 泛型方法

3.4 泛型接口

3.5 泛型的继承和通配符

4、Set集合

4.1 Set简介

4.2 HashSet

4.3 LinkedHashSet

4.4 TreeSet


1、集合的体系结构

List系列集合:添加的元素是有序、可重复、有索引
Set系列集合:添加的元素是无序、不重复、无索引

1.1 Collection

Collection是单列集合的祖宗接口,它的功能是全部单列集合都可以继承使用。

1.2 Collection的遍历方式

普通的for遍历Set不能使用,只能对List使用
1.2.1 迭代器遍历
迭代器在Java中的类是Iterator,迭代器是集合专用的遍历方式。
Collection集合获取迭代器:
Iterator中的常用方法:
如:
Iterator<String> it = list.iterator(); //创建指针
while(it.hasNext()){
    String str = it.next(); //判断是否有元素
    System.out.println(str); //获取元素,移动指针
}
细节注意:
  • 指向空位置报错,NoSuchElementException
  • 迭代器遍历完毕,指针不会复位
  • 循环中只能用一次next方法
  • 迭代器遍历时,不能用集合的方法进行增加或者删除
1.2.2 增强for遍历
  • 增强for的底层就是迭代器,为了简化迭代器的代码书写的
  • 它是JDK5之后出现的,其内部原理就是一个Iterator迭代器
  • 所有的 单列集合数组才能用增强for进行遍历
如:
for(String s : list) {
    System.out.println(s);
}
增强for的细节:
  • 修改增强for中的变量,不会改变集合中原本的数据
1.2.3 Lambda表达式遍历
例:
coll.forEach(s -> System.out.println(s));


2、List集合

2.1 List简介

List集合的特点:
  • 有序:存和取的元素顺序一致
  • 有索引:可以通过索引操作元素
  • 可重复:存储的元素可以重复
List集合的特有方法:

2.2 List集合特有的遍历方式:

2.2.1  普通for循环
for(int i = 0; i < list.size(); i++){
    String s = list.get(i);
    System.out.println(s);
}
2.2.2 列表迭代器遍历
ListIterator,继承自Iterator
ListIterator<String> it = list.listIterator();
while(it.hasNext()){
    String str = it.next();
    if("bbb".equals(str)){
        it.add("qqq");
    }
}
2.2.3 五种遍历方式对比

2.3 List的实现类

2.3.1 ArrayList集合

ArrayList集合底层原理:
  1. 利用空参创建的集合,在底层创建一个默认长度为0的数组(数组名为elementData,变量Size记录长度0)
  2. 添加第一个元素时,底层会创建一个新的长度为10的数组(其余未赋值的数据空间存储为null,Size随之改变)
  3. 存满时,会扩容1.5倍
  4. 如果一次添加多个元素,1.5倍还放不下,则新创建数组长度以实际值为准
原码:

2.3.2 LinkedList集合

底层是双向链表
特有API:
原码:


3、泛型深入

3.1 泛型

泛型:是JDK5中引入的特性,可以在编译阶段约束操作的数据类型,并进行检查
泛型的格式:
<数据类型>
注意:
  • 型只能支持引用数据类型,要用基本数据类型需要用包装类
  • 如果不给集合指定泛型,默认所有的数据类型都是Object类,可以添加任意数据,但无法使用它的特有行为
泛型好处:
  • 统一数据类型
  • 把运行时期的问题提前到了编译期间,避免了强制转换数据类型可能出现的异常,因为在编译阶段类型就确定下来了
扩展:Java中的泛型是伪泛型,只在存入数据时检查数据类型,实际操作中仍当成Object类型处理

3.2 泛型类

使用场景:当一个类中,某个变量的数据类型不确定时,就可以定义带有泛型的类
格式:
修饰符 class 类名 <类型> {
}
此处E可以理解为变量,但不是用来记录数据的,而是记录数据类型的,可写T,E,K,V

3.3 泛型方法

方法中形参类型不确定时,可以使用类名后面定义的泛型<E>
格式:
修饰符 <类型> 返回值类型 方法名(类型 变量名) {
}
此处T可以理解为变量,但是不是用来记录数据的,而是记录类型的,可以写成T,E,K,V等

3.4 泛型接口

格式:
修饰符 interface 接口名<类型>{
}
泛型接口两种使用方式:
  1. 实现类给出具体的类型
  2. 实现类延续泛型,创建实现类对象时再确定类型

3.5 泛型的继承和通配符

  • 泛型不具备继承性,但数据具备继承性
应用场景:
  • 如果我们在定义类,方法,接口的时候,类型不确定,可以定义泛型类,泛型方法,泛型接口
  • 如果类型不确定,但是能知道以后只能传递某个继承体系中的,就可以用泛型的通配符
  • 关键点:可以限定泛型的范围


4、Set集合

4.1 Set简介

Set系列集合:添加的元素是无序。不重复。无索引的
Set集合的实现类:
  • HashSet:无序、不重复、无索引
  • LinkedHashSet: 有序、不重复、无索引
  • TreeSet: 可排序、不重复、无索引

4.2 HashSet

HashSet底层原理
  • HashSet集合底层采用哈希表存储数据
  • 哈希表是一种对于增删改查数据性能都较好的结构
哈希表组成:
  • JDK8以前:数组+链表
  • JDK8开始:数组+链表+红黑树
哈希值:
  • 根据hashCode方法计算出来的int类型的整数
  • 该方法定义在Object类中,所有对象都可以调用,默认使用地址值进行计算
  • 一般情况下,会重写hashCode方法,利用对象内部类的属性值计算哈希值
对象的哈希值特点:
  • 如果没有重写hashCode方法,不同对象计算出的哈希值是不同的
  • 如果已经重写hashCode方法,不同的对象只要属性值相同,计算出的哈希值就是一样的
  • 在小部分情况下,不同的属性值或者不同的地址值计算出来的哈希值也有可能一样(哈希碰撞)
存入数据过程:
注意:
  • JDK8以后,当链表长度超过8,而且数组长度大于等于64,时,自动转换为红黑树
  • 如果存储自定义对象,则必须重写hashCode方法和equals方法

4.3 LinkedHashSet

有序:指按存入数据顺序
底层原理:
底层数据结构依然是哈希表,只是每一个元素又额外多了一个双链表的机制记录存储的顺序

4.4 TreeSet

可排序:指按照元素默认规则(由小到大)排序
底层原理:
TreeSet集合底层是基于红黑树实现排序的,增删改查性能都较良好
TreeSet集合默认的规则:
  • 对于数值类型:都是按照从小到大排序
  • 对于字符、字符串类型:都是按照ASCII码表中的数字升序进行排序
TreeSet的两种比较方式:
  1. 默认排序/自然排序:JavaBean类实现Comparable接口指定比较规则
  2. 比较器排序:创建TreeSet对象时,传递比较器Comparator指定规则
使用规则:默认用第一种,如果第一种不能满足需求用第二种
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

平凡的蒟蒻99

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值