集合和数组都是容器
数组的特点:
数组定义完成并启动后,类型确定,长度固定
在进行增删数据操作的时候,数组是不太适合的,增删数据都需要放弃原有数组或者移位
集合的特点:
Collection集合体系
Collection 集合特点:
集合对于泛型的支持:
集合都是支持泛型的,可以在编译阶段约束集合只能操作某种数据类型
// 存储基本数据类型使用包装类 Collection<Integer> list = new ArrayList<>();
集合和泛型不支持基本类型,只支持引用数据类型
Collection是单例集合的祖宗接口,它的功能是全部单例集合都可以继承使用的
package collection; import java.lang.reflect.Array; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; public class Main { public static void main(String[] args) { // HashSet:添加的元素都是无序,不重复,无索引的 Collection<String> list = new ArrayList<>(); // 添加元素:添加成功返回true list.add("java"); list.add("python"); list.add("C"); System.out.println(list); // 清空集合的元素 // list.clear(); // 判断集合是否为空,是则返回true System.out.println(list.isEmpty()); // 获取集合的大小 System.out.println(list.size()); // 判断集合中是否包含某个元素 System.out.println(list.contains("python")); // 删除某个元素:如果有多个重复元素,默认删除前面的第一个 System.out.println(list.remove("C")); // 把集合转换成数组 Object[] arrs = list.toArray(); // 注意不能集合里面不能完全确定一种数据类型 System.out.println("数组内容:" + Arrays.toString(arrs)); System.out.println("-------------------扩展-----------------------"); Collection<String> c1 = new ArrayList<>(); Collection<String> c2 = new ArrayList<>(); c2.addAll(c1); // 把C1中的元素全部导入c2中 } }
迭代器遍历的概述:
集合获取迭代器
方法名称 | 说明 |
---|---|
Iterator<E> iterator() |
返回集合中的迭代器对象,该迭代器默认指向当前集合的首地址 |
迭代器常用方法
方法名称 | 说明 |
---|---|
boolean hasNext() |
询问当前位置是否有元素存在,存在返回true |
E next() |
获取当前位置的元素,并同时将迭代器对象移向下一个位置,注意防止取出越界 |
package collection; import java.util.ArrayList; import java.util.Collection; import java.util.Iterator; public class Main { public static void main(String[] args) { Collection<String> lis = new ArrayList<>(); lis.add("李华"); lis.add("赵华"); lis.add("张华"); lis.add("小华"); System.out.println(lis); // 得到当前集合的迭代器对象 Iterator<String> it = lis.iterator(); while (it.hasNext()) { // 遍历迭代器对象 System.out.println(it.next()); } } }
增强for循环
格式:
for (元素数据类型 变量名: 数组或者Collection集合) { // 在此处使用变量即可,该变量就是元素 }
package collection; import java.util.ArrayList; import java.util.Collection; public class Main { public static void main(String[] args) { Collection<String> lis = new ArrayList<>(); lis.add("李华"); lis.add("赵华"); lis.add("张华"); lis.add("小华"); System.out.println(lis); for (String ele: lis) { // 在遍历内部修改元素值是无意义的,其不会改变原来的值 System.out.println(ele); } } }
Lambda表达式遍历集合:
Collection结合Lambda遍历API:forEach()
package collection; import java.util.ArrayList; import java.util.Collection; import java.util.function.Consumer; public class Main { public static void main(String[] args) { Collection<String> lis = new ArrayList<>(); lis.add("李华"); lis.add("赵华"); lis.add("张华"); lis.add("小华"); System.out.println(lis); lis.forEach(new Consumer<String>() { @Override public void accept(String s) { System.out.println(s); } }); lis.forEach(s -> { System.out.println(s); }); } }
方法名称 | 说明 |
---|---|
public static <T> void sort(List<T> list) |
将集合中元素按照默认规则排序 |
public static <T> void sort(List<T> list, Comparator<? super T> c) |
将集合中的元素指定规则进行排序 |
方法名称 | 说明 |
---|---|
public static <T> boolean addAll(Collection<? super T> c, T...elements) |
给集合对象批量添加元素 |
public static void shuffle(List<?> list) |
打乱List集合元素的顺序 |
数据结构是计算机底层存储,组织数据的方式。是指数据相互之间是以什么方式排列在一起的
通常情况下,精心选择的数据结构可以带来更高的运行或者存储效率
常见的数据结构:
栈数据结构的执行特点:
数据进入栈模型的过程称为:压栈、进栈
数据离开栈模型的过程称为:弹栈、出栈
队列数据结构的执行特点:
数据从后端进入队列模型的过程称为:入队列
数据从前端离开队列模型的过程称为:出队列
内存中的连续区域
特点:
数组是一种查询快,增删慢的模型
特点:
链表是一种查询慢、增删快的模型(对比数组)
单向链表
双向链表
二叉树里面存储了:父节点地址、值、左子节点地址、右子节点地址
特点:
二叉查找树又称二叉排序树或者二叉搜索树
特点:
目的:提高检索数据的性能
存储规则:
小的存左边
大的存右边
一样的不存
平衡二叉树是在满足查找二叉树的大小规则下,让树尽可能矮小,以此提高查数据的性能
要求:
平衡二叉树在添加元素后可能导致不平衡
平衡二叉树旋转的四种情况
红黑树是一种自平衡的二叉查找树,是计算机科学中用到的一种数据结构
每一个节点可以是红或者黑;红黑树不是通过高度平衡的,它的平衡是通过“红黑规则”进行实现的
红黑规则:
添加节点:
红黑树增删改查的性能都很好
ArrayList、 LinkedList:有序、可重复、有索引
List集合因为支持索引,所以多了解索引操作的独特API,其他Collection的功能List也都继承了
方法名称 | 说明 |
---|---|
void add(int index, E element) |
在此集合中的指定索引插入指定的元素 |
E remove(int index) |
删除指定索引处的元素,返回被删除的元素 |
E get(int index) |
返回指定索引处的元素 |
E set(int index, E element) |
修改指定索引处的元素,返回被修改的元素 |
package collection; import java.util.ArrayList; import java.util.List; import java.util.function.Consumer; public class Main { public static void main(String[] args) { List<String> lis = new ArrayList<>(); lis.add("李华"); lis.add("赵华"); lis.add("张华"); lis.add("小华"); System.out.println(lis); // 索引遍历 for (int i = 0; i < lis.size(); i++) { System.out.println(lis.get(i)); } // foreach遍历 lis.forEach(s -> { System.out.println(s); }); // 还有其他的遍历方法 } }
方法名称 | 说明 |
---|---|
public void addFirst(E e) |
在该列表开头插入指定的元素 |
public void addLast(E e) |
在指定的元素追加到此列表的末尾 |
public E getFirst() |
返回此列表中的第一个元素 |
public E getLast() |
返回此列表中的最后一个元素 |
public E removeFirst() |
从此列表中删除并返回第一个元素 |
public E removeLast() |
从此列表中删除并返回最后一个元素 |
LinkedList 可以完成队列结构和栈结构(双链表)
泛型:是JDK5中引入的特性,可以在编译阶段约束操作的数据类型,并进行检查
泛型的格式:<数据类型>;注意:泛型只能支持引用数据类型
集合体系的全部接口和实现类都是支持泛型的使用的
泛型的好处:
泛型可以在很多地方进行定义:
定义类时,同时定义了泛型的类就是泛型类
泛型类的格式:修饰符 class 类名<泛型变量>{}
class A<T> { // 此处泛型变量T可以随便写为任意标识,常见的如E/T/K/V等 }
作用:编译阶段可以指定数据类型,类似于集合的作用
模拟ArrayList集合自定义一个集合:
package collection; import java.util.ArrayList; public class MyArrayList<E> { // 需求,模拟ArrayLIst定义一个泛型设计 private ArrayList<E> lis = new ArrayList<>(); public void add(E e) { // 添加数据功能 lis.add(e); } public void remove(E e) { // 移除数据功能 lis.remove(e); } @Override public String toString() { // 输出功能 return lis.toString(); } }
定义方法的同时定义了泛型方法就是泛型方法
泛型方法的格式:修饰符 <泛型变量> 方法返回值类型 方法名称(形参列表){}
package collection; public class Main { public static void main(String[] args) { show("hello"); // 自动判断数据类型 } public static <T> void show(T t) { System.out.println(t); } }
泛型方法的核心思想:
作用:
使用了泛型定义的接口就是泛型接口
泛型接口的格式:修饰符 interface 接口名称 <泛型变量>{}
作用:泛型接口可以让实现类选择当前功能需要操作的数据类型
package collection; public interface Data<T> { // 对数据进行操作 void add(T s); void delete(T s); T queryById(int id); }
?
可以在“使用泛型”的时候代表一切类型
泛型的上下限:
? extend Car
:必须是Car或者其子类,泛型上限? super Car
:必须是Car或者其父类,泛型下限特点:
实现类特点:
Set系列的API大部分继承自Collection,几乎没有新的API
package set_; import java.util.HashSet; import java.util.Iterator; import java.util.Set; public class SetDemo { public static void main(String[] args) { // 创建 Set<String> sets = new HashSet<>(); // 添加数据 sets.add("hello"); sets.add("world"); sets.add("python"); // 移除数据 sets.remove("hello"); System.out.println(sets); // 遍历数据 for (String s: sets) { System.out.println(s); } sets.forEach(s -> { System.out.println(s); }); Iterator<String> it = sets.iterator(); // 转换成迭代器 while (it.hasNext()) { System.out.println(it.next()); } } }
HashSet集合底层原理采取哈希表存储的数据
哈希表是一种对于增删改查数据性能都较好的结构
组成:
哈希值:
public int hashCode()
:返回对象的哈希值哈希值特点:
hashCode()
方法返回的哈希值是相同的Set集合去重原理,先判断哈希值,再判断equals
如果是要进行自定义数据类型以及复杂数据类型的去重,需要我们重写equals
和hashCode
方法
特点:有序、不重复、无索引
原理:底层数据结构依然是哈希表,只是每个元素又额外多了一个双链表的机制记录存储的顺序
特点:不重复、无索引、可排序
可排序:按照元素的大小默认升序(由小到大)排序
TreeSet集合底层是基于红黑树的数据结构实现排序的,增删改查性能都较好
集合默认排序规则:
对于数值类型:默认安装大小进行升序排序
对于字符串类型:默认按照首字符的编号升序排序
对于自定义类型:TreeSet无法直接排序,需要制定排序规则
让自定义的类实现Comparable
接口,重写里面的compareTo
方法来定制比较规则
package set_; import org.jetbrains.annotations.NotNull; public class Student implements Comparable<Student>{ public Integer id; public String name; public Integer age; /** * 方式一:类自定义比较规则 * @param o * @return */ @Override public int compareTo(@NotNull Student o) { // 根据id升序排序,两个相等返回0,前面大于后面返回正数 return this.id - o.id; // 会去掉重复的元素 // return this.id - o.id >= 0 ? 1 : -1; // 保留id重复的元素 } }
TreeSet集合有参数构造器,可以设置Comparator
接口对应的比较器对象,来定制比较规则
Set<Student> stus = new TreeSet<>(new Comparator<Student>() { @Override public int compare(Student o1, Student o2) { return o1.id - o2.id; // 根据id值升序 } }); Set<Student> stus = new TreeSet<>((Student o1, Student o2) -> { return o1.id - o2.id; // 也可以结合匿名函数,浮点型建议直接使用Double.Compare();方法 });
如果TreeSet集合存储的对象有实现比较规则,集合也自带比较器,默认使用集合自带的比较器排序
可变参数用在形参中可以接收多个数据
可变参数的格式:数据类型...参数名称
作用:
可变参数的注意事项:
package set_; import java.util.Arrays; public class SetDemo { public static void main(String[] args) { sum(1); sum(1, 2, 3); sum(new int[]{1, 3, 6, 2}); } public static void sum(int...sum_) { System.out.println(Arrays.toString(sum_)); // 输出整型数组的内容 } }
Map集合是一种双列集合,每个元素包含两个数据
Map集合的每个元素的格式:key=value(键值对元素)
Map集合也被称为:“键值对集合”
Map集合体系特点:
Map集合实现类特点:
HashMap:元素按照键是无序,不重复,无索引,值不做要求。(与Map体系一致)
// 创建一个Map集合对象 Map<String, Integer> maps = new HashMap<>(); maps.put("笔记本", 23); System.out.println(maps);
Map是双列集合的祖宗接口,它的功能是全部双列集合都可以继承使用的
方法名称 | 说明 |
---|---|
V put(K key, V value) |
添加元素 |
V remove(Object key) |
根据键删除键值对元素 |
void clear() |
移除所有的键值对元素 |
boolean containsKey(Object key) |
判断集合中是否包含指定的键 |
boolean containsValue(Object value) |
判断集合是否包含指定的值 |
boolean isEmpty() |
判断集合是否为空 |
int size() |
集合的长度,也就是集合中键值对的个数 |
先获取Map集合的全部键的Set集合
遍历键的Set集合,然后通过键提取对应值
方法名称 | 说明 |
---|---|
Set<K> keySet() |
获取所有键的集合 |
V get(Object key) |
根据键获取值 |
package set_; import java.util.HashMap; import java.util.Map; import java.util.Set; public class SetDemo { public static void main(String[] args) { // 创建一个Map集合对象 Map<String, Integer> maps = new HashMap<>(); maps.put("笔记本", 23); maps.put("IPad", 234); maps.put("IPhone", 345); System.out.println(maps); // 遍历Map集合 Set<String> keys = maps.keySet(); for (String s: keys) { System.out.println(maps.get(s)); } } }
先把Map集合转换成Set集合,Set集合中每个元素都是键值对实体类型了
遍历Set集合,然后提取键以及提取值
方法名称 | 说明 |
---|---|
Set<Map.Entry<K, V>> entrySet() |
获取所有键值对对象的集合 |
K getKey() |
获得键 |
V getValue() |
获取值 |
package set_; import java.util.HashMap; import java.util.Map; import java.util.Set; public class SetDemo { public static void main(String[] args) { // 创建一个Map集合对象 Map<String, Integer> maps = new HashMap<>(); maps.put("笔记本", 23); maps.put("IPad", 234); maps.put("IPhone", 345); System.out.println(maps); // 遍历Map集合 Set<Map.Entry<String, Integer>> entries = maps.entrySet(); // 获取键值对组成的集合 for (Map.Entry<String, Integer> entry: entries) { System.out.println("键为:" + entry.getKey() + "\n值为:" + entry.getValue()); } } }
得益于JDK8开始的新技术Lambda表达式,提供了一种更简单、更直接的遍历集合的方式
package set_; import java.util.HashMap; import java.util.Map; import java.util.function.BiConsumer; public class SetDemo { public static void main(String[] args) { // 创建一个Map集合对象 Map<String, Integer> maps = new HashMap<>(); maps.put("笔记本", 23); maps.put("IPad", 234); maps.put("IPhone", 345); System.out.println(maps); // 遍历Map集合 maps.forEach((String s, Integer integer) -> { System.out.println(s + "====" + integer); }); } }
使用最多的Map集合是HashMap
特点:
实际上:Set系列集合的底层就是Map实现的,只是Set集合中的元素只要键数据,不要值数据而已
HashMap的特点和底层原理:
特点:
特点:
TreeMap集合自定义排序规则有2中:
特点:
Set<String> names = Set.of("李华", "张三"); // 这个集合是不可以改变的 Map<String, Integer> maps = Map.of("华为", 2, "Java", 4); // 这个Map也是不可以改变的
什么是Stream流?
Stream流的思想:
作用:
Stream流的三类方法:
获取Stream流的方式:
stream()
生成流名称 | 说明 |
---|---|
default Stream<E> stream() |
获取当前集合对象的Stream流 |
数组获取Stream流的方式:
名称 | 说明 |
---|---|
public static<T> Stream<T> stream(T[] array) |
获取当前数组的stream流 |
public static<T> Stream<T> of(T...values) |
获取当前数组/可变数据的Stream流 |
String[] names = {"hello", "world"}; Stream<String> nameStream = Array.stream(names); Stream<String> nameStream2 = Stream.of(names);
即为中间操作方法
名称 | 说明 |
---|---|
Stream<T> filter(Predicate<? super T> predicate) |
用于对流中数据进行过滤 |
Stream<T> limit(long maxSize) |
获取前几个元素 |
Stream<T> skip(long n) |
跳过前几个元素 |
Stream<T> distinct() |
去除流中重复的元素,依赖hashCode和equals |
static<T> Stream<T> concat(Stream a, Stream b) |
合并a和b两个流为一个流 |
注意:
名称 | 说明 |
---|---|
R collect(Collect collector) |
开始收集Stream流,指定收集器 |
Collection工具类提供了具体的收集方式
名称 | 说明 |
---|---|
public static<T> Collector toList() |
把数据收集到List集合中 |
public static<T> Collector toSet() |
把数据收集到Set集合中 |
public static Collector toMap(Function keyMapper, Function valueMapper) |
把数据收集到Map集合 |
package set_; import java.util.List; import java.util.ArrayList; import java.util.stream.Collectors; import java.util.stream.Stream; public class SetDemo { public static void main(String[] args) { List<String> lis = new ArrayList<>(); lis.add("李华"); lis.add("赵华"); lis.add("张华"); lis.add("小华"); System.out.println(lis); Stream<String> s = lis.stream().filter(s_ -> s_.startsWith("张")); // 注意,流只能使用一次 // Object[] arrs_t = s.toArray(); // 返回类数组,后面可以进行类型转换 // String[] arrs = s.toArray(String[]::new); // 直接返回字符串数组 System.out.println(s.collect(Collectors.toList())); // 转换为List集合。使用这个方法,s.toList(),返回不可变集合 } }
还有其他的接口,以及集合,大家可以通过官方文档查找