集合
1、数组和集合的元素存储的个数问题
数组定义后类型确定,长度固定
集合类型可以不固定,大小是可变的
2、数组和集合存储元素的类型问题
数组可以存储基本类型和引用类型的数据
集合只能存储引用数据类型的数据
3、数组和集合适合的场景
数组适合做数据个数和类型确定的场景
集合适合做数据个数不确定,且要做增删元素的场景。
一、Collection集合特点
List系列集合:添加的元素是有序、可重复、有索引。
ArrayList、LinekdList: 有序、可重复、有索引。
Set系列集合:添加的元素是无序、不重复、无索引。
HashSet: 无序、不重复、无索引;LinkedHashSet: 有序、不重复、无索引。
TreeSet:按照大小默认升序排序、不重复、无索引。
集合对于泛型的支持
集合都是支持泛型的,可以在编译阶段约束集合只能操作某种数据类型
Collection<string> lists = new ArrayList<string>();
Collection<String>lists = new ArrayList<>();// JDK 1.7开始后面的泛型类型中明可以省略不写
注意: 集合和泛型都只能支持引用数据类型,不支持基本数据类型,所以集合中存储的元素都认为是对象
如果集合中要存储基本类型的数据怎么办?
//存储基本类型使用包装类
Collection<Integer> lists = new ArrayList<>();
Collection<Double> lists = new ArrayList<>();
二、Collection常用API
1、添加元素,成功返回true
list.add("Java");
System.out.println(list.add("Java")); //true
2、清空集合元素
list.clear();
3、判断集合是否为空
System.out.printin(list.isEmpty());
4、获取集合大小
System.out.println(list.size());
5、判断集合中是否包含某个元素
System.out.println(list.contains("Java")); //true
6、删除某个元素,如果有多个则删除最前面的一个
System.out.println(list.remove("Java")); //true
7、把集合转换成数组
Object[] arrs =list.toArray();
8、两个集合合并
c1.addAll(c2); //把c1的元素拷贝到c2
三、Collection集合的遍历方式
迭代器遍历
遍历就是一个一个的把容器中的元素访问一遍
迭代器在Java中的代表是lterator,迭代器是集合的专用遍历方式
Iterator<String> it = lists.iterator();
String ele = it.next();
while(it.hasNext()){
String ele = it.next();
System.out.println(ele);
}
增强for循环
增强for循环:既可以遍历集合也可以遍历数组。
它是JDK5之后出现的,其内部原理是一个lterator迭代器,遍历集合相当于是迭代器的简化写法。
实现iterable接口的类才可以使用迭代器和增强for,Collection接口已经实现了iterable接口。
格式
for(元素数据类型 变量名:数组或者Collection集合){
//在此处使用变量即可,该变量就是元素
}
举例说明
Collection<String> list = new ArrayList<>0;//多态
...
for(String ele : list) {
System.outprintln(ele);
}
1、增强for可以遍历哪些容器?
既可以遍历集合也可以遍历数组
2、增强for的关键是记住它的遍历格式
for(元素数据类型 变量名: 数组或者Collection集合)//在此处使用变量即可,该变量就是元素
lambda表达式
Lambda表达式遍历集合
得益于JDK 8开始的新技术Lambda表达式,提供了一种更简单、更直接的遍历集合的方式
Collection结合Lambda遍历的API
default void forEach(Consumer<? super T> action): //结合lambda遍历集合
四、Collection集合存储自定义类型的对象
1、数据结构概述
数据结构是计算机底层存储、组织数据的方式。是指数据相互之间是以什么方式排列在一起的。
通常情况下,精心选择的数据结构可以带来更高的运行或者存储效率
2、常见的数据结构
(1)、栈、队列
栈 ----
后进先出,先进后出
队列 ----
先进先出,后进后出
(2)、数组
数组是一种查询快,增删慢的模型
查询速度快:查询数据通过地址值和索引定位,查询任意数据耗时相同。(元素在内存中是连续存储的)
删除效率低:要将原始数据删除,同时后面每个数据前移。
添加效率极低:添加位置后的每个数据后移,再添加元素。
(3)、链表
链表的特点
链表中的元素是在内存中不连续存储的,每个元素节点包含数据值和下一个元素的地址。
链表查询慢。无论查询哪个数据都要从头开始找
链表增删相对快
链表的种类
单向链表
双向链表
(3)、二叉树、二叉查找树
二叉树的特点
只能有一个根节点,每个节点最多支持2个直接子节点。
节点的度:节点拥有的子树的个数,二又树的度不大于2叶子节点度为0的节点,也称之为终端结点。
高度:叶子结点的高度为1,叶子结点的父节点高度为2以此类推,根节点的高度最高。
层: 根节点在第一层,以此类推
兄弟节点: 拥有共同父节点的节点互称为兄弟节点
二叉查找树特特点
每一个节点上最多有两个子节点
左子树上所有节点的值都小于根节点的值
右子树上所有节点的值都大于根节点的值
二叉查找树又称二叉排序数或者二叉搜索树。
目的:提高检索数据的性能。
(4)、平衡二叉树
平衡二叉树是在满足查找二叉树的大小规则下,让树尽可能矮小,以此提高查数据的性能。
平衡二叉树的要求
任意节点的左右两个子树的高度差不超过1,任意节点的左右两个子树都是一颗平衡二叉树。
平衡二叉树在添加元素后可能导致不平衡
基本策略是进行左旋,或者右旋保证平衡
(5)、红黑树
红黑树概述
红黑树是一种自平衡的二叉查找树,是计算机科学中用到的一种数据结构。
972年出现,当时被称之为平衡二叉B树。1978年被修改为如今的"红黑树”。
每一个节点可以是红或者黑,红黑树不是通过高度平衡的,它的平衡是通过“红黑规则”进行实现的。
红黑规则
每一个节点或是红色的,或者是黑色的,根节点必须是黑色。
果一个节点没有子节点或者父节点,则该节点相应的指针属性值为NiL,这些Nl视为叶节点,叶节点是黑色的。
如果某一个节点是红色,那么它的子节点必须是黑色(不能出现两个红色节点相连的情况)。
对每一个节点,从该节点到其所有后代叶节点的简单路径上,均包含相同数目的黑色节点。
添加节点
添加的节点的颜色,可以是红色的,也可以是黑色的。
默认用红色效率高
红黑树小结
规则如下:
每一个节点或是红色的,或者是黑色的,根节点必须是黑色
如果一个节点没有子节点或者父节点,则该节点相应的指针属性值为Nil,这些Ni视为叶节点,每个叶节点(Ni)是黑色的;
如果某一个节点是红色,那么它的子节点必须是黑色(不能出现两个红色节点相连的情况)
对每一个节点,从该节点到其所有后代叶节点的简单路径上,均包含相同数目的黑色节点。
红黑树增删改查的性能都很好
各种数据结构的特点和作用是什么样的
队列:先进先出,后进后出。
栈:后进先出,先进后出。
数组:内存连续区域,查询快,增删慢。
链表:元素是游离的,查询慢,首尾操作极快。
二叉树:永远只有一个根节点,每个结点不超过2个子节点的树。
查找二叉树:小的左边,大的右边,但是可能树很高,查询性能变差。
平衡查找二叉树:让树的高度差不大于1,增删改查都提高了。
红黑树(就是基于红黑规则实现了自平衡的排序二叉树)。
4、List系列集合
List<String> list = new ArrayList<>();
修改索引数据
System.out.println(list.set(1,"Mysql"));
(1)List系列集合特点
ArrayList、LinekdList: 有序,可重复,有索引。
(2)List的实现类的底层原理
ArrayList底层是基于数组实现的,根据查询元素快,增删相对慢
LinkedList底层基于双链表实现的,查询元素慢,增删首尾元素是非常快的。
(3)List集合的遍历方式有几种?
迭代器
增强for循环
Lambda表达式
for循环(因为List集合存在索引)
(4)ArrayList集合底层原理
ArrayList底层是基于数组实现的: 根据索引定位元素快,增删需要做元素的移位操作。
第一次创建集合并添加第一个元素的时候,在底层创建一个默认长度为10的数组。
(5)LinkedList集合的底层原理
LinkedList的特点
底层数据结构是双链表,查询慢,首尾操作的速度是极快的,所以多了很多首尾操作的特有API。
LinkedList集合的特有功能
方法名称 |
说明 |
public void addFirst(E e) |
在该列表开头插入指定的元素 |
public void addLast(E e) |
将指定的元素追加到此列表的末尾 |
public E getFirst() |
返回此列表中的第一个元素 |
public E getLast() |
返回此列表中的最后一个元素 |
public E removeFirst() |
从此列表中删除并返回第一个元素 |
public E removeLast() |
从此列表中删除并返回最后一个元素 |
5、补充知识:集合的并发修改异常问题
问题引出
当我们从集合中找出某个元素并删除的时候可能出现一种并发修改异常问题
哪些遍历存在问题?
迭代器遍历集合且直接用集合删除元素的时候可能出现。
增强for循环遍历集合且直接用集合删除元素的时候可能出现。
哪种遍历且删除元素不出问题
迭代器遍历集合但是用迭代器自己的删除方法操作可以解决。
使用for循环遍历并删除元素不会存在这个问题。
6、补充知识:泛型深入
泛型概述
泛型:是]DK5中引入的特性,可以在编译阶段约束操作的数据类型,并进行检查
泛型的格式:<数据类型>;注意:泛型只能支持引用数据类型
集合体系的全部接口和实现类都是支持泛型的使用的。
泛型的好处:
统一数据类型。
把运行时期的问题提前到了编译期间,避免了强制类型转换可能出现的异常,因为编译阶段类型就能确定下来。
泛型可以在很多地方进行定义:
类后面 ——> 泛型类
方法申明上 ——> 泛型方法
接口后面 ——> 泛型接口
自定义泛型类
泛型类的概述
定义类时同时定义了泛型的类就是泛型类
泛型类的格式:修饰符 class 类名<泛型变量>
范例: public class MyArrayList<T>{}
此处泛型变量T可以随便写为任意标识,常见的如E、T、K、V等
作用:编译阶段可以指定数据类型,类似于集合的作用。
自定义泛型方法
泛型方法的概述
定义方法时同时定义了泛型的方法就是泛型方法。
泛型方法的格式:修饰符<泛型变量>方法返回值方法名称(形参列表){}
范例: public <T> void show(T t){}
作用:方法中可以使用泛型接收一切实际类型的参数,方法更具备通用性
泛型方法的原理:
把出现泛型变量的地方全部替换成传输的真实数据类型
泛型方法的核心思想
把出现泛型变量的地方全部替换成传输的真实数据类型
泛型方法的作用
方法中可以使用泛型接收一切实际类型的参数,方法更具备通用性
自定义泛型接口
泛型接口的概述
使用了泛型定义的接口就是泛型接口
泛型接口的格式:修饰符 interface 接口名称<泛型变量>0
范例: public interface Data<E>{}
作用:泛型接口可以让实现类选择当前功能需要操作的数据类型
泛型接口的原理:
实现类可以在实现接口的时候传入自己操作的数据类型,这样重写的方法都将是针对于该类型的操作。
泛型接口的作用
泛型接口可以约束实现类,实现类可以在实现接口的时候传入自己操作的数据类型这样重写的方法都将是针对于该类型的操作。
泛型通配符、上下限
通配符:?
?可以在“使用泛型”的时候代表一切类型。
E T K V是在定义泛型的时候使用的。
泛型的上下限:
?extends Car:?必须是Car或者其子类泛型上限
? super Car: ?必须是Car或者其父类 泛型下限