我们于2021/07/19 的学习目标是:容器,核心任务为:
1、学习技术:
1)、Collection 集合上层接口与List接口
2)、List的添加与删除
3)、List的遍历
4)、List 接口的实现类
5)、LinkedList
6)、通过单向链表简单实现扩容
2、文档总结
1)、Collection 集合上层接口与List接口
Collection集合上层接口:
- 存储单个数据值,多个元素的集合
- 常用方法
- 遍历方式:foreach与迭代器Iterator
- Map 多个元素的集合,每个元素由键值对组成
List 接口
- 有序可重复
- 新增:一些根据索引操作的方法
- 添加null元素
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
public class Class001_List {
public static void main(String[] args) {
//List容器
/*
泛型: 规定集合存储数据的类型 | 规定数据的类型
表示 : <数据类型> 数据类型只能为引用数据类型
位置 : 定义在数据类型的后面
优点 : 帮助增强程序的稳定性与可读性
*/
List<String> list = new ArrayList();
//List<Integer> list2 = new ArrayList();
list.add(null);
list.add(null);
list.add("abc");
list.add("cde");
list.add("mnb");
System.out.println(list);
//新增方法
//void add(int index, E element) 将指定元素插入此列表中的指定位置(可选操作)。
list.add(1,"你好");
System.out.println(list);
//E get(int index) 返回此列表中指定位置的元素。
System.out.println(list.get(3));;
//int indexOf(Object o) 返回此列表中第一次出现的指定元素的索引,如果此列表不包含该元素,则返回-1。
//int lastIndexOf(Object o) 返回此列表中指定元素最后一次出现的索引,如果此列表不包含该元素,则返回-1。
System.out.println(list.lastIndexOf(null));
//static <E> List<E> of(E... elements) 返回包含任意数量元素的不可修改列表。
List<Integer> list1 = List.of(1,2,3,4,5);
System.out.println(list1);
//E remove(int index) 删除此列表中指定位置的元素(可选操作)。
System.out.println(list.remove(2));
System.out.println(list);
//E set(int index, E element) 用指定的元素替换此列表中指定位置的元素(可选操作)。
System.out.println(list.set(4,"nb"));
System.out.println(list);
//List<E> subList(int fromIndex, int toIndex) 返回指定的 fromIndex (包含)和 toIndex (不包括)之间的此列表部分的视图。
System.out.println(list.subList(1,3));
System.out.println(list);
//Object[] toArray()
System.out.println(Arrays.toString(list.toArray()));
}
}
2)、List的添加与删除
有序:存放的顺序与内部真实存储的顺序相同
注意:存储的数据为整数的时候,默认以索引优先
import java.util.ArrayList;
import java.util.List;
public class Class002_List {
public static void main(String[] args) {
List<Integer> list = new ArrayList<>();
list.add(3);
list.add(1);
list.add(2);
list.add(5);
list.add(4);
List<Boolean> list2 = new ArrayList<>();
list2.add(false);
list2.add(true);
list2.add(false);
list2.add(true);
System.out.println(list2);
//删除
list.remove(3);
System.out.println(list);
/*移出第一个数据*/
list2.remove(false);
System.out.println(list2);
}
}
3)、List的遍历
List集合遍历方式:
普通for循环
for(int i=0;i<list.size();i++){}
增强for循环
for(String str : list){}
iterator迭代器
for(Iterator<String> it = list.iterator();it.hasNext();){}
ListIterator迭代器
ListIterator<String> it2 = list.listIterator();
while(it2.hasNext()){}
反向遍历
ListIterator<String> it3 = list.listIterator(4);
while(it3.hasPrevious()){
System.out.println(it3.previousIndex()+"-->"+it3.previous());
}
4)、List 接口的实现类
特点:有序、可重复
ArrayList:
底层实现: 可变数组
特点:
根据索引做查询效率高
增删效率低,设计到新数组的创建,数据的拷贝等问题
应用场景: 大量做查询,少量做增删的时候适合使用ArrayList
扩容:
int newCapacity = oldCapacity + (oldCapacity >> 1);
通过Arrays.copyOf方法实现扩容,每次扩容原容量的1.5倍
第一次添加数据内部构建数组的初始容量为10
新增内容:
void forEach(Consumer<? super E> action)
对 Iterable每个元素执行给定操作,直到处理 Iterable所有元素或操作引发异常。
遍历方式:
- 普通for
- 增强for
- iterator迭代器
- listIterator迭代器
定义ArrayList,存储自定义的javabean类型学生类型数据,简单操作
Vector 向量
特点:有序,可重复
底层结构:数组
与ArrayList很像
Vector与 ArrayList之间的区别:
同步问题 | 扩容问题 | |
ArrayList | 线程不安全|不同步,相对效率高 | 每次扩容原容量的1.5倍,更有利于节约内存 |
Vector | 线程安全|同步 | 每次扩容原容量的2倍 |
注意:使用集合存储自定义引用数据类型数据时候,需要重写equals方法,使用indexOf,constains()..,默认使用equals的返回值决定是否存在,包含,相等
可以实现比较对象的内容,而非地址
import com.yjx.entity.Student;
import java.util.ArrayList;
import java.util.List;
public class Class004_ArrayList{
public static void main(String[] args) {
//ArrayList() 构造一个初始容量为10的空列表。
List<String> list = new ArrayList<>();
//ArrayList(int initialCapacity) 构造具有指定初始容量的空列表。
//ArrayList(Collection<? extends E> c) 按照集合的迭代器返回的顺序构造一个包含指定集合元素的列表。
//添加
list.add("haha");
list.add("hehe");
System.out.println(list);
//遍历输出每一个元素
list.forEach(System.out::println);
//定义存储学生信息的集合
ArrayList<Student> stus = new ArrayList();
stus.add(new Student("a",19,"j"));
stus.add(new Student("b",20,"k"));
stus.add(new Student("c",18,"l"));
System.out.println(stus);
System.out.println(stus.indexOf(new Student("b",20,"k")));
System.out.println(stus.contains(new Student("c",18,"l")));
}
}
5)、LinkedList
底层结构: 双向链表
特点:有序,可重复
根据索引查询效率低
做增删效率高
应用场景:大量做增删少量做查询的时候适合使用
新增功能:新增了一些可以直接操作头尾的方法
import java.util.LinkedList;
public class Class005_LinkedList {
public static void main(String[] args) {
//链表结构
LinkedList<Double> linked = new LinkedList<>();
//添加
linked.add(1.1);
linked.add(2.1);
linked.add(3.1);
linked.add(4.1);
System.out.println(linked);
//首位添加
linked.addFirst(0.1);
//末尾添加
linked.addLast(5.1);
System.out.println(linked);
//移除首位
System.out.println(linked.removeFirst());
System.out.println(linked);
}
}
6)、通过单向链表简单实现扩容
package com.yjx.list03;
public class Class006_MyLinkedList {
public static void main(String[] args) {
MyLinkedList list = new MyLinkedList();
System.out.println(list.size());
//list.add("haha");
System.out.println(list.size());
//list.add("haha");
System.out.println(list.size());
System.out.println(list);
}
}
//自定义的链表
class MyLinkedList{
//记录链表头节点
private Node head;
private int size;
public MyLinkedList() {
}
/**
* 在链表结构的最后添加一个数据
* @param value 要添加的数据
*/
public void add(Object value) {
//1.创建新节点
Node node = new Node(value,null);
//2.判断是否为第一个节点,作为链表头节点
if (head == null && size == 0){
head = node;
//长度+1
size++;
return;
}
//3.存在原链表.遍历原链表,找到原链表的最后一个节点,新节点挂上去
//定义一个临时变量,指向首节点
Node temp = head;
while(temp.getNext()!=null){
//指向下一个节点
temp = temp.getNext();
}
//新节点地址挂在原链表的最后
temp.setNext(node);
//4.长度+1
size++;
}
//size()
public int size(){
return this.size;
}
//toString()
@Override
public String toString(){
StringBuilder sb = new StringBuilder("[");
//临时变量用于遍历这个链表
Node temp = head;
//遍历链表结构
while(temp!=null){
// 获取到每一个节点的数据值,拼接到字符串中
sb.append(temp.getData()+", ");
//temp指向下一个节点
temp = temp.getNext();
}
String str = sb.toString();
//判断字符串是否以, 结尾,如果是去掉,
if(str.endsWith(", ")){
str = str.substring(0,str.length()-2);
}
return str+"]";
}
}
//链表中的节点
class Node{
private Object data;
private Node next; //Node next = new Node();
public Node(Object data, Node next) {
this.data = data;
this.next = next;
}
public Object getData() {
return data;
}
public void setData(Object data) {
this.data = data;
}
public Node getNext() {
return next;
}
public void setNext(Node next) {
this.next = next;
}
@Override
public String toString() {
return "Node{" +
"data=" + data +
", next=" + next +
'}';
}
}