15-集合进阶上
单列集合顶层接口Collection
- List系列集合:添加的元素是有序,可重复,有索引的
- Set系列集合:添加的元素是无序,不重复,无索引的
- Collection是单列集合的祖宗接口,他的功能是全部单列集合都可以继承使用
迭代器
package io.xiaoduo.arrayListForward;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
public class Test2 {
public static void main(String[] args) {
Collection<String> coll = new ArrayList<>();
coll.add("aaa");
coll.add("bbb");
coll.add("ccc");
coll.add("ddd");
// 创建指针
Iterator<String> it = coll.iterator();
while (it.hasNext()) {
String item = it.next();
System.out.println(item);
}
}
}
细节注意点
- 没有下一个报错
NoSuchElementException
- 迭代器遍历完毕,指针不会复位
- 循环中只能用一次next方法
- 迭代器遍历时,不能用集合的方法进行增加或者删除
增强for遍历
- 增强for的底层就是迭代器,为了简化迭代器的代码书写
- JDK5之后出现的,其内部原理就是一个Iterator迭代器
- 所有的单列集合和数组才能用增强for进行遍历
- 修改增强for中的变量不会改变集合中原本的数据
lambda表达式forEach遍历
- js警告
list.forEach((s) -> { sout(s); });
List中的常见的方法和五种遍历方式
- List集合的遍历方式
- 迭代器遍历
- 列表迭代器遍历
- 增强for遍历
- Lambda表达式遍历
- 普通for循环(因为List集合存在索引)
package io.xiaoduo.arrayListForward;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
public class Test4 {
public static void main(String[] args) {
List<String> arr = new ArrayList<>();
arr.add("aaa");
arr.add("bbb");
arr.add("ccc");
Iterator<String> it = arr.iterator();
while (it.hasNext()) {
String str = it.next();
System.out.println(str);
}
System.out.println("------");
ListIterator<String> lit = arr.listIterator();
while (lit.hasNext()) {
String str = lit.next();
System.out.println(str);
}
System.out.println("------");
for (String s : arr) {
System.out.println(s);
}
System.out.println("------");
arr.forEach(item -> System.out.println(item));
System.out.println("------");
arr.forEach(System.out::println);
System.out.println("------");
for (int i = 0; i < arr.size(); i++) {
String item = arr.get(i);
System.out.println(item);
}
}
}
数据结构
栈
队列
数组
链表
ArrayList底层原理
- 利用空参创建集合的时候,在底层创建一个长度为0的数组
- 添加第一个元素时,底层会创建一个新的长度为10的数组
- 存满时会扩容1.5倍
- 如果一次添加多个元素,1.5倍还放不下,则新创建数组的长度以实际为准
LinkedList集合
- 底层数据结构是双向链表,查询慢,首尾操作的速度是极快的,所以多了很多首尾操作的特有api
泛型深入
- 泛型:是JDK5中引入的特性,可以在编译阶段约束操作的数据类型,并进行检查
- 泛型的格式:<数据类型>
- 注意:泛型只能支持引用数据类型
泛型的好处
- 统一数据类型
- 把运行时期的问题提前到了编译阶段,避免了强制类型转换可能出现的异常,因为在编译阶段就能确定下来
泛型的细节
- 泛型中不能写基本数据类型
- 指定泛型的具体类型后,传递数据时,可以传入该类型或者其子类类型
- 如果不写泛型,类型默认是Object
泛型可以在很多地方定义
– | – |
---|---|
类后面 | 泛型类 |
方法上面 | 泛型方法 |
接口后面 | 泛型接口 |
泛型类
- 使用场景:当一个类中,某个变量的数据类型不确定时,就可以定义带有泛型的类
泛型方法
修饰符 <类型> 返回值类型 方法名(类型 变量名) {}
public <T> void fn(T t) {}
泛型接口
修饰符 interface 接口名<类型> {}
public interface List(T) {}
泛型的继承和通配符通配符
- 泛型不具备继承性,泛型里面写的是什么类型,就只能传递什么类型的数据,但数据具备继承性
- 泛型的通配符:?
- ? extend E
- ? super E
哪里定义泛型
- 泛型类:在类名后面定义泛型,创建该类对象的时候,确定类型
- 泛型方法:在修饰符后面定义泛型,调用该方法的时候,确定类型
- 泛型接口:在接口后面定义泛型,实现类确定类型,实现类延续泛型
使用场景
- 定义类,方法,接口的时候,如果类型不确定,就可以定义泛型
- 如果类型不确定,但是能知道是哪个继承体系中的,可以使用泛型的通配符
数据结构
二叉树
二叉查找树
平衡二叉树
红黑树
Set集合
- Set系列集合的特点
- 无序、不重复、无索引
- Set集合的方法上基本与Collection的API一致
- Set集合的实现类特点
- HashSet:无序、不重复、无索引
- LinkedHashSet:有序、不重复、无索引
- TreeSet:可排序、不重复、无索引
- HashSet底层原理
- 创建一个默认长度16,默认加载为0.75的数组,数组名table
- 根据元素的哈希值跟数组的长度计算尺应存入的位置
- 判断当前位置是否为null,如果是null直接存入
- 如果位置不为null,表示有元素,则调用equals方法比较属性值
- 一样:不存;不一样:存入数组,形成链表
- JDK8以前:新元素存入数组,老元素挂在新元素下面
- JDK8以后:新元素直接挂在老元素下面
- LinkedHashSet集合的特点和原理是怎样的
- 有序、不重复、无索引
- 底层基于哈希表,使用双链表记录添加顺序
- 在以后如果要数据去重,我们使用哪个
- 默认使用HashSet
- 如果要求去重且存取有序,才使用LinkedHashSet
- TreeSet集合的特点是怎样的
- 可排序、不重复、无索引
- 底层基于红黑树实现排序,增删改查性能好
- TreeSet集合自定义排序规则有几种方式
- 方式一:Javabean类实现Comparable接口,指定比较规则
- 方式二:创建集合时,自定义Comparator比较器对象,指定比较规则
- 方法返回值的特点
- 负数:表示当前要添加的元素是小的,存左边
- 正数:表示当前要添加的元素是大的,存右边
- 0:表示当前要添加的元素已存在,舍弃
总结
- 如果想要集合中的元素可重复
- 用ArrayList集合,基于数组的(用的最多)
- 如果想要集合中的元素可重复,而且当前的增删操作明显多于查询
- 用LinkedList集合,基于链表的
- 如果想对集合中的元素去重
- 用HashSet集合,基于哈希表的(用的最多)
- 如果想要对集合中的元素去重,而且保证存取有序
- 用LinkedHashSet集合,基于哈希表和双链表,效率低于HashSet
- 如果想要对集合中的元素进行排序
- 用TreeSet集合,基于红黑树,后续也可以用List集合实现排序