Day07
今日内容
- 集合的概述和集合继承体系
- Collection集合
- List集合
- ArrayList集合
- LinkedList集合
- 数据结构
- 源码【不建议过深的去研究】
今日目标
- 集合继承体系【了解】
- Collection集合特点及常用API【应用、理解】
- List集合特点及常用API【应用、理解】
- ArrayList集合【应用、理解】
- LinkedList集合【应用、理解】
- 数据结构【理解】
01-集合和数组的对比
- 问题:ArrayList和数组的区别?
1.大小(长度):
数组:长度不可变
集合:可变的(自动扩容)
2.定义(存储的数据类型):
数组:基本数据类型和引用数据类型
集合:引用数据类型(包括基本数据类型的包装类)
02-集合的体系结构
- 问题:集合分为哪两大类
Collection 单列集合
Map 双列集合
- 问题:ArrayList属于哪一类集合?
Collection 单列
- 体系结构
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-E08ONwyz-1634922812639)(day07随堂笔记.assets/集合体系.png)]
03-Collection常见成员方法
- 添加元素
boolean add(E e) 添加成功返回true 失败返回false
- 从集合中移除指定元素
boolean remove(Object o) 删除成功返回true 失败返回false
- 根据条件进行删除
default boolean removeIf(Predicate<? super E> filter) 删除成功返回true 失败返回false
- 清空集合
void clear()
- 判断集合中是否存在指定的元素
boolean contains(Object o) 存在返回true 不存在返回false
- 判断集合是否为空 空代表没有数据 长度是0
boolean isEmpty() 为空返回true 不为空返回false
- 集合的长度,集合元素的个数
int size()
- 代码
public class MyCollectonDemo2 {
public static void main(String[] args) {
Collection<String> collection = new ArrayList<>();
// boolean add(E e) 添加元素
collection.add("aaa");
collection.add("bbb");
collection.add("ccc");
collection.add("dddd");
//System.out.println(collection);
//method1(collection);
//method2(collection);
//method3(collection);
//method4(collection);
//method5(collection);
//method6(collection);
}
private static void method6(Collection<String> collection) {
// int size() 集合的长度,也就是集合中元素的个数
int size = collection.size();
System.out.println(size);
}
private static void method5(Collection<String> collection) {
// boolean isEmpty() 判断集合是否为空
collection.clear();
boolean result = collection.isEmpty();
System.out.println(result);
}
private static void method4(Collection<String> collection) {
// boolean contains(Object o) 判断集合中是否存在指定的元素
boolean result = collection.contains("a");
System.out.println(result);
boolean result2 = collection.contains("aaa");
System.out.println(result2);
}
private static void method3(Collection<String> collection) {
// void clear() 清空集合
//就是将集合中所有的元素全部删除.
collection.clear();
System.out.println(collection);
}
private static void method2(Collection<String> collection) {
// boolean removeif(Object o) 根据条件进行删除
//removeif底层会遍历集合,得到集合中的每一个元素
//s依次表示集合中的每一个元素
//就会把这每一个元素都到lambda表达式中去判断一下
//如果返回的是true,则删除
//如果返回的是false,则保留不删除.
//boolean test(String t);
collection.removeIf(
(String s)->{
return s.length() == 3;
}
);
System.out.println(collection);
}
private static void method1(Collection<String> collection) {
// boolean remove(Object o) 从集合中移除指定的元素
//如果删除成功了,则返回true
//如果删除失败了,则返回false
boolean result1 = collection.remove("aaa");
boolean result2 = collection.remove("ddd");
System.out.println(result1);
System.out.println(result2);
System.out.println(collection);
}
}
- 需要注意的方法
- 扩展
contains 依赖存储对象的equals方法
- 匿名内部类或者lambda表达式
removeIf
- 判断的是size()是否等于0
isEmpty()
04-Collection迭代器基本使用
- 问题:迭代器的作用是什么?
- 遍历集合
- 问题:迭代器的两个成员方法的【作用】是什么?
判断当前索引位置是否有元素
boolean hasNext()
1.取出当前索引的元素
2.向后移了一位
E next()
- 迭代器的使用,代码
Collection<String> list = new ArrayList<>();
list.add("a");
list.add("b");
list.add("c");
list.add("d");
list.add("e");
Iterator<String> it = list.iterator();
while(it.hasNext()){
String s = it.next();
System.out.println(s);
}
05-Collection迭代器原理分析
- 分析
// 获取一个迭代器对象,初识指向集合0索引处
Iterator<String> it = list.iterator();
// 判断当前位置是否有元素可以被取出
it.hasnext()
// 取出当前位置的元素
// 将迭代器对象移向下一个索引位置
it.next()
- debug
关注Iterator中【cursor】变量
06-Collection迭代器删除方法
- 理解for循环中删除两个相邻的元素,不能删除成功
根本原因:ArrayList可变,当删除一个元素后,后面的元素会向前移动补齐
// 现象:相邻两个元素 后一个删除不成功
// 原因:集合的长度变化了(缩短)
// 解决办法:每次删除成功i--
// 迭代器的remove()
- 断点debug调试
ArrayList<String> list = new ArrayList<>();
list.add("a");
list.add("b");
list.add("b");
list.add("c");
list.add("d");
for (int i = 0; i < list.size(); i++) {
String s = list.get(i); // 断点位置:关注变量i、list.size()、s
if("b".equals(s)){
list.remove(i);
}
}
- 迭代器的删除方法不会出现上述问题
根本原因 迭代器remove方法,迭代器中的cursor变量, 执行了 cursor–;操作
- debug:
ArrayList<String> list = new ArrayList<>();
list.add("a");
list.add("b");
list.add("b");
list.add("c");
list.add("d");
Iterator<String> it = list.iterator();
while(it.hasNext()){
String s = it.next(); // 断点位置:关注变量s、it中的cursor
if("b".equals(s)){
it.remove();
}
}
System.out.println(list);
07-增强for基本格式
- 问题:增强for底层使用什么实现的遍历?
迭代器
- 问题:集合使用增强for,需要实现什么接口?单列集合(Collection)、双列集合(Map)谁实现了这个接口?
Iterable
单列集合实现了这个接口
- 问题:哪些类型可以使用增强for?
数组
所有的单列集合
- 格式
for(元素的数据类型 变量名 : 数组或Collection集合){
//使用变量,变量就代表元素
}
for(Integer i : arrayList){
System.out.println(i);
}
- 示例
// 集合
ArrayList<String> arrayList = new ArrayList<>();
for (String str : arrayList) {
System.out.println(str);
}
// 数组
int[] arr = new int[5];
for (int i : arr) {
System.out.println(i);
}
08-增强for注意点
- 增强for中的变量理解
- 对比普通for循环理解 增强for循环中的变量
- 所谓的第三方变量
for(Integer i : arrayList){
i = 10;
System.out.println(i);
}
for (int i = 0; i < arrayList.size(); i++) {
Integer intt = arrayList.get(i);
intt = 10;
}
- 问题:三种遍历方式使用场景是什么?
- 普通for 需要操作索引的时候
- 增强for 仅仅遍历用
- 迭代器 遍历时删除元素(可以避免:相邻两个元素 后一个删除不成功)
09-Collection-练习
- 两种方式遍历Collection集合
思路:
- 定义学生类
- 创建Collection集合对象
- 创建学生对象
- 把学生添加到集合
- 迭代器遍历集合
- 增强for遍历集合
10-List-概述和基本使用
- 问题:List集合有什么特点?
1.有序:存取有序
2.有索引:通过索引操作元素
3.可重复:存储的元素可以重复
- 基本使用(Collection相关API)、遍历方式
11-List-特有方法
根据索引操作
void add(int index, E element) 在集合中指定位置插入元素,原来位置的元素向后移动一位
E remove(int index) 删除指定索引处的元素,返回被删除的元素,后面的元素向前补齐
boolean remove(Object o) 删除成功返回true 失败返回false
E set(int index, E element) 修改指定索引处的元素,返回被修改的元素
E get(int index) 返回指定索引处的元素
12-数据结构-栈和队列
- 栈特点
像弹夹,数据先进后出
应用:
- 栈内存
- 队列特点
像排队,数据先进先出
应用:
- ArrayBlockingQueue 多线程当中用到的队列
13-数据结构-数组和链表
- ArrayList中处理数组(可变数组)的特点
可变数组:代码实现的
- 查询:通过数组的地址,找数组的索引
- 查询快
- 添加:中间插入数据,后面其他数据依次向后移动
- 删除:删除中间的数据,后面其他数据依次向前移动补齐
- 增删慢
- 链表的特点
- 增加、删除:只要换节点的地址值就行了
- 增删快,相对数组
- 查询:从头节点依次向后找
- 查询慢,相对数组
- 单向链表:一个节点记录下一个节点地址值
- 双向链表:一个节点记录前后节点的地址值,查询时距离头尾哪边近,就从哪边找
14-ArrayList-源码解析
- debug
// 1.ArrayList<String> list = new ArrayList<>();创建一个长度为0的空数组
// 2.每次扩容容量为原容量的1.5倍
public class Test8 {
public static void main(String[] args) {
//
ArrayList<String> list = new ArrayList<>();
/*
1.elementData底层数组的变量名
2.Object[] 空数组 {}
public ArrayList() {
this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}
*/
list.add("aaa");
/*
public boolean add(E e) {
modCount++;
1.e 要添加的 aaa
2.elementData 底层数组
3.size 当前操作的索引:0
add(e, elementData, size);
return true;
}
*/
/*
private void add(E e, Object[] elementData, int s) { 第一个参数:aaa 第二个参数:{} 第三个参数:0
// 什么情况下扩容:当前指向的索引值等于数组的长度 装满了
if (s == elementData.length)
// 调用扩容方法 grow() 返回一个扩容后的数组
// elementData底层数组 = 扩容后的数组
elementData = grow();
// 把当前要添加的值 赋值到0索引的位置
elementData[s] = e;
// size = 0 + 1 指向了1索引位置
size = s + 1;
}
*/
/*
private Object[] grow() {
// 调用了一个有参的grow方法 并且传的值是size + 1
return grow(size + 1);
}
*/
/*
private Object[] grow(int minCapacity) { 参数:1
Arrays.copyOf 复制原数组的数据到一个长度为10的数组中,返回给 elementData 底层数组
return elementData = Arrays.copyOf(elementData,
newCapacity(minCapacity));
}
*/
/*
private int newCapacity(int minCapacity) { 参数minCapacity: 1
// overflow-conscious code
1.oldCapacity旧容量:0
int oldCapacity = elementData.length;
2.newCapacity新容量= 旧容量 * 1.5 目前的值是0
int newCapacity = oldCapacity + (oldCapacity >> 1); (n + n / 2)
3.判断 0 - 1 是不是小于等于0
if (newCapacity - minCapacity <= 0) {
4.{} = {}
if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA)
5.去两个值得最大值
DEFAULT_CAPACITY:10
minCapacity:10
return Math.max(DEFAULT_CAPACITY, minCapacity);
if (minCapacity < 0) // overflow
throw new OutOfMemoryError();
return minCapacity;
}
return (newCapacity - MAX_ARRAY_SIZE <= 0)
? newCapacity
: hugeCapacity(minCapacity);
}*/
}
}
15-LinkedList-基本运用
- 基本使用(Collection相关API)、遍历方式
16-LinkedList-特有功能
public void addFirst(E e) 在列表开头插入指定的元素
public void addLast(E e) 将指定的元素追加到此列表的末尾
public E getFirst() 返回此列表的第一个元素
public E getLast() 返回此列表的最后一个元素
public E removeFirst() 从此列表删除并返回第一个元素
public E removeLast() 从此列表删除并返回最后一个元素
- 当集合中只有一个元素的时候,getFirst 和 getLast 获取的是一样的
- 当集合中没有元素的时候 removeFirst 和 removeLast 会报异常:NoSuchElementException
17-LinkedList-源码解析
-debug
public class Test10 {
public static void main(String[] args) {
/*public class LinkedList{
// 头结点
Node first = null;
// 尾节点
Node last = null;
}*/
/*
Node内部类
private static class Node<E> {
E item; 节点中存的值
Node<E> next; 下一个节点的地址值
Node<E> prev; 上一个节点的地址值
构造方法
Node(Node<E> prev, E element, Node<E> next) { 上一个,值,下一个
this.item = element;
this.next = next;
this.prev = prev;
}
}
*/
/*
从尾部追加
void linkLast(E e) {
1.尾节点记录到 l 变量中
final Node<E> l = last;
2.创建一个节点 传参:尾节点,值,null
3.这个节点的
上一个: 当前的尾节点地址值
值: 要添加的值
下一个: null
final Node<E> newNode = new Node<>(l, e, null);
4.把新的节点变成了尾节点
last = newNode;
5.如果第一次添加,尾部应该是null
if (l == null)
first = newNode;
6.否则让节点的(下一个)指向新节点
else
l.next = newNode;
size++;
modCount++;
}*/
LinkedList<String> list = new LinkedList<>();
list.add("aaa");
list.add("bbb");
list.add("ccc");
}
}
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-PRyi2waE-1634922812641)(day07随堂笔记.assets/链表.png)]
- 扩展
// 把一个集合中的所有数据添加到另一个集合当中
// addAll(Collection collection)
ArrayList<String> list1 = new ArrayList<>();
list1.add("aaa");
list1.add("bbb");
LinkedList<String> list2 = new LinkedList<>();
list2.add("qqq");
list2.add("ttt");
list1.addAll(list2);
System.out.println(list1);
// 用一个集合里面的数据创建另一个集合
LinkedList<String> list = new LinkedList<>();
list.add("aaa");
list.add("bbb");
list.add("ccc");
ArrayList<String> arrayList = new ArrayList<>(list);
System.out.println(arrayList);