第六天、集合-Collection&List&Set
集合
体系概述
集合体系结构
-
Collection 代表单列集合,每个元素(数据)只包含一个值
-
Map 代表双列集合,每个元素包含两个值(键值对)
Collection集合体系
Collection集合特点
-
List系列集合 : 有序,可重复(ArrayList LinekdList)
-
Set系列集合 : 无序,不可重复(HashSet LinkedHashSet : 存取有序 TreeSet : 可排序)
Collection的常用方法
为啥要先学Collectionde常用方法?
-
Collection是单列集合的祖宗,它规定的方法(功能)是全部单列集合都会继承的
Collection的常见方法如下
Collection的遍历方式
迭代器概述
-
迭代器是用来遍历集合的专用方式(数组没有迭代器),在Java中迭代器的代表是Iterator
Collection集合获取迭代器的方法
Iterator迭代器中的常用方法
增强for循环
-
格式 : for (元素的数据类型 变量名 : 数组或者集合) { 内容 }
-
增强for可以用来遍历集合或者数组
-
增强for遍历集合,本质就是迭代器遍历集合的简化写法
Lambda
Lambda表达式遍历集合
-
Lambda表达式,提供了一种更简单、更直接的方式来遍历集合
需要使用Collection的如下方法来完成
-
格式 : lists.forEach(s -> { System.out.println(s); });//其前身为内部匿名类的写法
集合存储对象的原理
-
对象集合中存储对的是元素对象的地址
Collection的并发修改异常
集合的并发修改异常
-
使用迭代器遍历集合时,又同时在删除集合中的数据,程序就会出现并发修改异常的错误
-
由于增强for循环遍历集合就是迭代器遍历集合的简化写法,因此,使用增强for循环遍历集合,又在同时删除集合中的数据时,程序也会出现并发修改异常的错误
怎么保证遍历集合同时删除数据时不出bug?
-
使用迭代器遍历集合:但用迭代器自己的删除方法删除数据即可
-
使用增强for循环遍历集合:无法解决这个问题
-
使用普通for循环遍历集合:可以倒着遍历并删除;或者从前往后遍历,但删除元素后做i --操作
List集合
List特有方法
List集合的特有方法
-
List集合因为支持索引,所以多了很多与索引相关的方法,当然,Collection的功能List也都继承了
List集合支持的遍历方式
-
迭代器
-
增强for循环
-
Lambda表达式
-
for循环(因为List集合有索引)
ArrayList
-
ArrayList集合的底层原理
-
基于数组实现的
-
查询速度快(注意:是根据索引查询数据快): 查询数据通过地址值和索引定位,查询任意数据耗时相同
-
删除效率低 : 可能需要把后面很多的数据进行前移
-
添加效率极低:可能需要把后面很多的数据后移,再添加元素;或者也可能需要进行数组的扩容
-
ArrayList集合适用的场景
-
ArrayList适合 : 根据索引查询数据,比如根据随机索引取数据(高效)!或者数据量不是很大时
-
ArrayList不适合 : 数据量的同时,又要频繁的进行增删操作
LinkedList
LinkedList集合的底层原理
-
基于双链表实现的
-
什么是双链表?有什么特点?
-
链表中的结点是独立的对象,在内存中是不连续的,每个节点包含数据值和下一个节点的地址
-
特点1: 查询慢,无论查询那个数据都要从头开始找
-
特点2: 链表增删相对快
LinkedList新增了:很多首尾操作的特有方法
LinkedList的应用场景之一
-
可以用来设计队列 特点 : 先进先出,后进后出
-
可以用来设计栈 特点 : 后进先出,先进后出
Set集合
Collection集合体系
-
Set<E>(接口)第一类:HashSet<E>又分为:LinkedHashSet<E> 第二类:TreeSet<E>
Set系列 特点:无序;不可重复
-
HashSet
-
LinkenHashSet : 存取有序
-
TressSet : 可排序
HashSet
哈希值
-
int类型的数值,Java中每个对象都有哈希值
-
Java中所有对象都可以调用Obejct类提供的哈市Code方法,并返回自己的哈希值
-
public int hashCode():返回对象的哈希码值
对象哈希值的特点
-
同一对象多次调用hashCode()方法返回的哈希值是一样的
-
不同的对象,它们的哈希值一般不相同,也有可能相同(即为哈希碰撞)
-
Object的hashCode方法根据"对象地址"计算哈希值
-
子类重写后的hashCode方法可以根据"对象属性值"计算哈希值
HashSet集合的底层原理
-
基本哈希表实现
-
哈希表是一种增删改查数据,性能都比较好的数据结构
哈希表
-
JDK8之前,哈希表=数组+链表
-
JDK8开始,哈希表=数组+链表+红黑树
-
JDK8之前HashSet集合的底层原理,基于哈希表:数组+链表
-
创建一个默认长度16的数组,默认加载因子为0.75,数组名table
-
使用元素的哈希值对数组的长度求余计算出应存入的位置
-
判断当前位置是否为null,如果是null直接存入
-
如果不为null,表示有元素,则调用equals方法比较 相等,则不存;不相等,则存入数组
-
JDK 8之前,新元素存入数组,占老元素位置,老元素挂下面
-
JDK 8开始之后,新元素直接挂在老元素下面
注意
-
JDK8开始,当链表长度超过8,且数组长度>=64时,自动将链表转成红黑树
-
小结:JDK8开始后,哈希表中引入了红黑树后,进一步提高了操作数据的性能。
LinkedHashSet
LinkedHashSet底层原理
-
LinkedHashSet是不可重复的,存取有序的,底层是基于哈希表(数组、链表、红黑树)实现的。
-
但是,它的每个元素都额外的多了一个双链表的机制记录它前后元素的位置
TreeSet
TreeSet
-
特点:不重复、无索引、可排序(默认升序排序 ,按照元素的大小,由小到大排序)
-
底层是基于红黑树实现的排序
注意:
-
对于数值类型:Integer , Double,默认按照数值本身的大小进行升序排序。 对于字符串类型:默认按照首字符的编号升序排序。 对于自定义类型如Teacher对象,TreeSet默认是无法直接排序的
自定义排序规则
-
TreeSet集合存储自定义类型的对象时,必须指定排序规则,支持如下两种方式来指定比较规则。
-
方式一:自然排序 让自定义的类(如教师类)实现Comparable接口,重写里面的compareTo方法来指定比较规则。
-
方式二:比较器排序 通过调用TreeSet集合有参数构造器,可以设置Comparator对象(比较器对象,用于指定比较规则)。
总结
1、如果希望记住元素的添加顺序,需要存储重复的元素,又要频繁的根据索引查询数据? 用ArrayList集合(有序、可重复、有索引),底层基于数组的。(常用)
2、如果希望记住元素的添加顺序,且增删首尾数据的情况较多? 用LinkedList集合(有序、可重复、有索引),底层基于双链表实现的。
3、如果不在意元素顺序,也没有重复元素需要存储,只希望增删改查都快? 用HashSet集合(无序,不重复,无索引),底层基于哈希表实现的。 (常用)
4、如果希望记住元素的添加顺序,也没有重复元素需要存储,且希望增删改查都快? 用LinkedHashSet集合(有序,不重复,无索引), 底层基于哈希表和双链表。
5、如果要对元素进行排序,也没有重复元素需要存储?且希望增删改查都快? 用TreeSet集合,基于红黑树实现。