集合概述(集合和数组都是容器)
一.数组和容器的特点
1数组的特点:
(1)数组定义完成并启动后,类型确定、长度固定
(2)在进行增删数据操作的时候,数组是不太合适的,增删数据都需要放弃原有数组或移位
2数组适合的场景
(1)当业务数据的个数是固定的,且同同一批数据的时候,可以采取自定义数组存储
存储四种花色 : String[] colors = {"♠" , "♥" , "♣" , "♦"};
3集合的特点
(1)集合是Java中存储对象的一种容器
(2)集合的大小不固定,启动后可以动态变化,类型也可以选择不固定。集合更像气球
(3)集合非常适合做元素的增删操作
(4)注意:集合中只能存储引用类型数据,如果要存储基本类型数据可以使用包装类
4集合适合的场景
(1)数据的个数不确定,需要进行增删元素的时候
5总结
(1)数组和集合的元素存储的个数问题:
(I)数组定义后类型确定,长度固定
(II)集合类型可以不固定,大小是可变的
(2)数组和集合存储元素的类型问题
(I)数组可以存储基本类型和引用类型的数据
(II)集合只能存储引用数据类型的数据
(3)数组和集合适合的场景
(I)数组适合做数据个数和类型确定的场景
(II)集合适合做数据个数不确定,且要做增删元素的场景
Collection集合
一Collection集合的体系特点
1集合:Collection(单列) , Map(双列)
Collection单列集合,每个元素(数据)只包含一个值
map双列集合,每个元素包含两个值(键双列)
2Collection集合体系
(1)Collection集合特点
(I)List系列集合:添加的元素是有序、可重复、有索引
(a)ArrayList、LinekdList:有序、可重复、有索引
(2)Set系列集合:添加的元素是无序、不重复、无索引
(a)HashSet:无序、不重复;无索引;->LinkedHashSet:有序、不重复、无索引
(b)TreeSet:按照大小默认升序排序、不重复、无索引
3集合对泛型的支持
(1)集合都是支持泛型的,可以再编译阶段约束集合只能操作某种数据类型
Collection<String> lists = new ArrayList<String>();
Collection<String> lists = new ArrayList<>();JDK 1.7开始后面的泛型类型申明可以省略不写
(2)注意:集合和泛型都只能支持引用数据类型,不支持基本数据类型,所以集合中存储的元素都认为是对象
(3)如果集合中要存储基本类型的数据怎么办?
//存储基本类型使用包装类
Collection<Integer> lists = new ArrayList<>();
Collection<Double> list = new ArrayList<>();
4总结
(1)集合的代表是?
(I)Collection接口
(2)Collection集合分了哪两个大常用的集合体系
(I)List系列集合:添加的元素是有序、可重复、有索引
(II)Set系列集合:提那家的元素是无序、不重复、无索引
(3)如何约定集合存储数据的类型,需要注意什么?
(I)集合支持泛型
(II)集合和泛型不支持基本类型,只支持引用数据类型
二.Collection集合常用API
1Collection集合
(1)Collection是单列集合的祖宗接口,他的功能是全部单列集合都可以继承使用的
方法名称 | 说明 |
public boolean add(E e) | 把给定的对象添加到当前集合中 |
public void clear() | 清空集合中所有的元素 |
public boolean remove(E e) | 把给定的对象在当前集合中删除 |
public boolean cotains(Object ob) | 判断当前集合中是否包含给定的对象 |
public boolean isEmpty() | 判断当前集合是否为空 |
public int size() | 返回集合中元素的个数 |
public Object[] toArray() | 把集合中的元素,存储到数组中 |
三.Collection集合的遍历方式
(一)迭代器
(1)迭代器遍历概述
(I)遍历就是一个一个的把容器中的元素访问一遍
(II)迭代器在Java中的代表是Iterator,迭代器是集合的专用遍历方式。
(2)Collection集合获取迭代器
方法名称 | 说明 |
Iterator<E> iterator() | 返回集合中的迭代器对象,该迭代器对象默认指向当前集合的0索引 |
(3)Iterator中的常用方法
方法名称 | 说明 |
boolean hasNext() | 访问当前位置是否有元素存在,存在返回true,不存在返回false |
E next() | 获取当前位置的元素,并同时将迭代器对象移向下一个位置,注意防止取出越界 |
2总结
(1)迭代器的默认位置在哪里
(I)Iterator<E> iterator():得到迭代器对象,默认指向当前集合的索引0
(2)迭代器如果取元素越界会出现什么问题
(II)会出现NoSuchElementException异常
package com.itheima.d3_Collection_traversal;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
public class CollectionDemo01 {
public static void main(String[] args) {
Collection<String> lists = new ArrayList<>();
lists.add("赵敏");
lists.add("芦苇");
lists.add("青菜");
lists.add("土豆");
lists.add("面包");
System.out.println(lists);
//1得到当前集合的迭代器对象
Iterator<String> it = lists.iterator();
/*String ele = it.next();
System.out.println(ele);
System.out.println(it.next());
System.out.println(it.next());
System.out.println(it.next());*/
//2定义while循环
while (it.hasNext()){
String ele = it.next();
System.out.println(ele);
}
System.out.println("---------------------");
}
}
(二)foreach/增强for循环
1增强for循环
(1)增强for循环:既可以遍历集合也可以遍历数组。
(2)它是JDK5之后出现的,其内部原理是一个Iterator迭代器,遍历集合相当于是迭代器的简化写法
(3)实现Iterable接口的类才可以使用迭代器和增强for,Collection接口已经实现了Iterable接口
2格式
for(元素数据类型 变量名 :数组或者Collection集合){
//在此处使用变量即可,该变量就是元素
}
Colletion<String> list = new ArrayList<>();
...
for(String ele : list){
System.out.println(ele);
}
3总结:
(1)增强for可以遍历那些容器?
(I)既可以遍历集合也可以遍历数组
(2)增强for的关键是记住它的遍历格式
(I)for(元素数据类型 变量名 : 数组或者Collection集合){
//在此处使用变量即可 , 该变量就是元素
}
(三)lambda表达式
1Lambda表达式遍历集合
(1)得益于JDK 8 开始的新技术Lambda表达式,提供了一种更简单,更直接的遍历集合的方式。
Collection结合Lambda遍历的API
方法名称 | 说明 |
default void forEach(Cosumer<? super T> action) | 结合lambda遍历集合 |
Collection<String>list = new ArrayList<>();
...
lists.forEach(new Consumer<String>(){
@Override
public void accept(String s) {
System.out.println(s);
}
});
lists.forEach(s -> {System.out.println(s);});
lists.forEach(s -> System.out.println(s));
package com.itheima.d3_Collection_traversal;
import java.util.ArrayList;
import java.util.Collection;
import java.util.function.Consumer;
public class CollectionDemo03 {
public static void main(String[] args) {
Collection<String> lists = new ArrayList<>();
lists.add("赵敏");
lists.add("小昭");
lists.add("阿巴巴");
lists.add("土豆");
lists.add("炒青菜");
System.out.println(lists);
lists.forEach(new Consumer<String>() {
@Override
public void accept(String s) {
System.out.println(s);
}
});
/*lists.forEach( s -> {System.out.println(s);});*/
lists.forEach(System.out::println);
}
}
(三)Collection集合存储自定义类型的对象
案例:影片信息在程序中表示
需求:某影院系统需要在后台存储上述三部电影,然后依次展示出来。
分析:定义一个电影类,定义一个集合存储电影对象
创建3个电影对象,封装相关数据,把3个对象存入到集合中去
遍历集合中的3个对象,输出相关信息
总结:集合中存储的是元素的什么信息?:集合中存储的是元素对象的地址。
package com.itheima.d4_collection_object;
public class Movie {
private String name;
private double score;
private String actor;
public Movie() {
}
public Movie(String name, double score, String actor) {
this.name = name;
this.score = score;
this.actor = actor;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public double getScore() {
return score;
}
public void setScore(double score) {
this.score = score;
}
public String getActor() {
return actor;
}
public void setActor(String actor) {
this.actor = actor;
}
@Override
public String toString() {
return "Movie{" +
"name='" + name + '\'' +
", score=" + score +
", actor='" + actor + '\'' +
'}';
}
}
package com.itheima.d4_collection_object;
import java.util.ArrayList;
import java.util.Collection;
public class TestDemo {
public static void main(String[] args) {
//1定义一个电影类
//2定义一个集合对象存储3部电影对象
Collection<Movie> movies = new ArrayList<>();
movies.add(new Movie("《你好李焕英》" , 9.5 , "张晓雯,贾玲,沈腾,陈赫"));
movies.add(new Movie("《唐人街探案》" , 8.5 , "王宝强,刘昊然,美女"));
movies.add(new Movie("《刺杀小说家》" , 8.6 , "雷佳音,杨幂"));
System.out.println(movies);
//3遍历集合容器中的每个电影对象
for (Movie movie : movies) {
System.out.println("片名:" + movie.getName());
System.out.println("得分:" + movie.getScore());
System.out.println("主演:" + movie.getActor());
}
}
}
四.常见数据结构概述
(一)数据结构概述、栈、队列
1数据结构概述:
(1)数据结构是计算机底层出处、组织数据的方式。是指数据相互之间是以什么方式排列在一起的。
(2)通常情况下,精心选择的数据结构可以带来更高的运行或者存储效率
2常见的数据结构
栈 |
队列 |
数组 |
链表 |
二叉树 |
二叉查找树 |
平衡二叉树 |
红黑树 |
... |
3栈数据结构的执行特点
(1)后进先出,先进后出:
数据从后端进入队列模型的过程称为:入队列
数据从前端离开队列模型的过程称为:出队列
(二)数组
1常见数据结构之数组
(1)查询速度快:查询数据通过地址值和索引定位,查询任意数据耗时相等。(元素在内存中是连续存储的)
(2)删除效率低:要将原始数据删除:同时后面每个数据前移
(3)添加效率极低:添加位置后的每个数据后移,再添加元素
(三)链表
1链表的特点
(1)链表中的元素是在内存中不连续存储的,每个元素节点包含数据值和下一个元素的地址。
(2)链表查询慢。无论查询哪个数据都要从头开始找
(3)链表增删相对快
(四)二叉树、二叉查找树
1二叉树的特点
(1)只能有一个根节点,每个节点最多支持2个直接子节点
(2)节点的度:节点拥有的子树的个数,二叉树的度不超过2, 叶子节点度为0的节点也称为终端节点
2二叉查找树又称为二叉排序树或者二叉搜索树
特点:
(1)每一个节点上最多有两个子节点
(2)左子树上所有节点的值都小雨根节点的值
(3)右子树上所有节点的值都大于根节点的值
目的:
(1)提高检索数据的性能
(五)平衡二叉树
1二叉树查找存在的问题:出现瘸子现象,导致查询的性能与单链表一样,查询速度变慢!
2平衡二叉树的要求
(1)任意节点的左右两个子树的高度差不超过1,任意节点的左右两个子树都是一颗平衡二叉树
3平衡二叉树在添加元素后可能导致不平衡
(1)基本策略是进行左旋,或者右旋保证平衡
4平衡二叉树-旋转的四种情况
(1)左左(整体右)
(2)左右(错左整体右)
(3)右右(整体左)
(4)右左(错右整体左)
(六)红黑树
1红黑树概述:
(1)红黑树是一种自平衡的二叉查找树,是计算机科学中用到的一种数据结构。
(2)1972年出现,当时被称之为平衡二叉B树。1978年被修改为如今的“红黑树”。
(3)每一个节点可以是红或者黑;红黑树不是通过高度平衡的,他的平衡是通过“红黑规则”进行实现的。
(4)红黑树增删改查的性能都很好
2红黑规则:
(1)每一个节点或是红色的,或者是黑色的,根节点必须是黑色的。
(2)如果一个节点没有子节点或者父节点,则该节点相应的指针属性值为Nil,这些Nil视为叶节点,叶节点是黑色的。
(3)如果某一个节点是红色,那么它的子节点必须是黑色(不能出现两个红色节点相连的情况)
(4)对每一个节点,从该节点到其所有后代叶节点的简单路径上,均包含相同数目的黑色节点
3添加节点
(1)添加的节点的颜色,可以使红色的,也可以是黑色的
(2)默认用红色效率更高
五.List系列集合
(一)List集合特点、特有API
1List集合特有方法
(1)List集合因为支持索引,所以多了很多索引操作的独特api,其他Collection的功能List也都继承了
方法名称 | 说明 |
void add(int index , E element) | 在此集合中的指定位置插入指定元素 |
E remove(int index) | 删除指定索引处的元素,返回被删除的元素 |
E set(int index , E element) | 修改指定所引出的元素,返回被修改的元素 |
E get(int index) | 返回指定索引处的元素 |
2总结:
(1)List系列集合特点
(I)ArrayList、LinekdList:有序、可重复、有索引
(2)List的实现类的底层原理
(I)ArrayList底层是基于数组实现的,根据查询元素快,增删相对慢
(II)LinkedList底层基于双链表实现的,查询元素慢,增删首位元素是非常快的
(二)List集合的便利方式小结
1List集合的遍历方式有几种?
(1)迭代器 (2)增强for循环 (3)Lambda表达式 (4)for循环(因为List集合存在索引)
(三)ArrayList集合的底层原理
1ArrayList集合底层原理
(1)ArrayList底层是基于数组实现的:根据索引定位元素块,增删需要做元素的位移操作
(2)第一次创建集合并添加第一个元素的时候,在底层创建一个默认长度为10的数组
(四)LinkedList集合的底层原理
1LinkedList的特点
(1)底层数据结构是双链表,查询慢,首位操作的速度是极快的,所以多了很多首尾操作的特有API
2LinkedList集合的特有功能
方法名称 | 说明 |
public void addFirst(E e) | 在该列表开头插入指定的元素 |
public void addLast(E e) | 将指定的元素追加到此列表的末尾 |
public E getFirst() | 返回此列表中的第一个元素 |
public E getLast() | 返回此列表中的最后一个元素 |
public E removeFirst() | 从此列表中删除并返回第一个元素 |
public E removeLast() | 从此列表中删除并返回最后一个元素 |
package com.itheima.d5_collection_list;
import java.util.ArrayList;
import java.util.LinkedList;
public class ListDemo03 {
public static void main(String[] args) {
//LinkedList 可以完成列结构,和栈结构(双链表)
//栈
LinkedList<String> stack = new LinkedList<>();
//压栈 入栈
stack.push("第一颗子弹");
stack.push("第二颗子弹");
stack.addFirst("第三颗子弹");
stack.addFirst("第四颗子弹");
System.out.println(stack);
//出栈 弹栈
System.out.println(stack.pop());
System.out.println(stack.removeFirst());
System.out.println(stack.removeFirst());
System.out.println(stack);
//队列
LinkedList<String> queue = new LinkedList<>();
queue.addLast("1号");
queue.addLast("2号");
queue.addLast("3号");
queue.addLast("4号");
queue.addLast("5号");
//出队
System.out.println(queue.removeFirst());
System.out.println(queue.removeFirst());
System.out.println(queue.removeFirst());
System.out.println(queue);
}
}
六.补充知识:集合的并发修改异常问题
1问题引出:当我们从集合中找出某个元素并删除的时候可能出现一种并发修改异常问题。
2哪些遍历存在问题?
(1)迭代器遍历集合且直接用集合删除元素的时候可能出现
(2)增强for循环遍历集合且直接用集合删除元素的时候可能出现
3那种遍历且删除元素不出问题
(1)迭代器遍历集合但是用迭代器自己的删除方法操作可以解决
(2)使用for循环遍历并删除元素不会存在这个方法
package com.itheima.d6_collection_update_delete;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
public class Test {
public static void main(String[] args) {
//1准备数据
List<String> list = new ArrayList<>();
list.add("鸡蛋");
list.add("Java");
list.add("Java");
list.add("鹅蛋");
list.add("笨蛋");
list.add("蠢蛋");
System.out.println(list);
//需求:删除全部的Java信息
//a迭代器遍历删除
/*Iterator<String> it = list.iterator();
while (it.hasNext()){
String ele = it.next();
if ("Java".equals(ele)){
//list.remove("Java");
it.remove();//使用迭代器删除当前位置的元素,保证不后移,能够成功遍历到全部元素
// 使用删除当前所在元素,并且不会后移
}
}
System.out.println(list);*/
//b foreach遍历删除(会出现bug)
/*for (String s : list) {
if ("Java".equals(s)){
//list.remove("Java");
}
}
System.out.println(list);*/
//c lambda表达式(会出现bug)
/*list.forEach(s -> {
if ("Java".equals(s)) {
list.remove("Java");
}
});*/
//d for循环(不会出现异常错误,但是数据删除出现了问题:会漏掉元素)
/*for (int i = 0 ; i < list.size() ; i++){
String ele = list.get(i);
if ("Java".equals(ele)){
list.remove("Java");
}
}
System.out.println(list);*/
//解决方案
/*for (int i = list.size() - 1; i >= 0 ; i--){
String ele = list.get(i);
if ("Java".equals(ele)){
list.remove("Java");
}
}
System.out.println(list);*/
//解决方案2
for (int i = 0 ; i < list.size() ; i++){
String ele = list.get(i);
if ("Java".equals(ele)){
list.remove("Java");
i--;
}
}
System.out.println(list);
}
}
七.补充知识:泛型深入
(一)泛型概述和优势
1泛型概述
(1)泛型:是JDK4中引入的特性,可以在编译阶段约束操作的数据类型,并进行检查。
(2)泛型的格式:<数据类型>;注意:泛型只能支持引用数据类型
(3)集合体系的全部接口和实现类都是支持泛型的使用的
2泛型的好处
(1)统一数据类型
(2)吧运行时期的问题提前到了编译期间,避免了强制类型转换可能出现的异常,因为编译阶段类型就能确定下来
3泛型可以在很多地方进行定义:
类后面------------------------泛型类
方法申明上-----------------------------泛型方法
接口后面---------------------泛型接口
(二)自定义泛型类
1泛型类的概述
(1)定义类是同时定义了泛型的类就是泛型类。
(2)泛型类的格式:修饰符class类名<泛型变量>{ }
范例:public class MyArrayList<T>{ }
(3)此处泛型变量T可以随便写为任意标识、常见的如E、T、L、V等
(4)作用:编译阶段可以指定数据类型,类似于集合的作用。
2课程案例导学
(1)模拟ArrayList集合自定义一个集合MyArrayList集合,完成添加和删除功能的泛型设计即可。
3泛型类的原理:
(1)把出现泛型变量的地方全部替换成传输的真实数据类型
4总结:
(1)泛型类的核心思想:把出现泛型变量的地方全部替换成传输的真实数据类型。
(2)泛型类的租用:编译阶段约定操作的数据的类型,类似于集合的作用
package com.itheima.d8_genericity_class;
import java.util.ArrayList;
public class MyArrayList<E> {
private ArrayList lists = new ArrayList();
public void add(E e){
lists.add(e);
}
public void remove(E e){
lists.remove(e);
}
@Override
public String toString() {
return lists.toString();
}
}
package com.itheima.d8_genericity_class;
public class Test {
public static void main(String[] args) {
//需求:模拟ArrayList定义一个MyArrayList,关注泛型设计
MyArrayList<String> list = new MyArrayList<>();
list.add("Java");
list.add("Java");
list.add("MySQL");
list.remove("MySQL");
System.out.println(list);
MyArrayList<Integer> list2 = new MyArrayList<>();
list2.add(23);
list2.add(24);
list2.add(25);
list2.remove(25);
System.out.println(list2);
}
}
(三)自定义泛型方法
1泛型方法的概述
(1)定义方法时同时定义了泛型的方法就是泛型方法
(2)泛型方式的格式:修饰符<泛型变量>方法返回值 方法名称(形参列表){}
范例:public<T> void show(T t){}
(3)作用:方法中可以使用泛型接受一切实际类型的参数,方法更具备通用性.
2课程案例导学
(1)给你任何一个类型的数组,都能返回他的内容,也就是试下你Arrays.toString(数组)的功能!
3泛型方法的原理
(1)把出现泛型变量的地方全部替换成传输的真实数据类型
4总结
(1)泛型方法的核心思想:把出现泛型变量的地方全部替换成传输的真实数据类型
(2)泛型方法的作用:方法中可以使用泛型就收一切实际类型的参数,方法更具备通用性
(四)自定义泛型接口
1泛型接口的概述
(1)使用了泛型定义的借口就是泛型接口
(2)泛型接口的格式:修饰符interface 接口名称<泛型变量>{}
范例:public interface Data<E>{}
(3)作用:泛型接口可以让实现类选择当前功能需要操作的数据类型
2课程案例导学
(1)教务系统,提供一个接口可约束一定要完成数据(学生,老师)的增删改查操作
3泛型接口的原理:
(1)实现类可以在实现接口的时候传入自己操作的数据类型,这样重写的方法都将是针对于该类型的操作
4总结:
(1)泛型接口的作用:泛型接口可以约束实现类,实现类可以在实现接口的时候传入自己操作的数据类型这样重写的方法都将是针对于该类型的操作。
package com.itheima.d10_genericity_interface;
public interface Data<E> {
void add(E s);
void delete(int id);
void update(E e);
E queryById(int id);
}
package com.itheima.d10_genericity_interface;
public class Student {
}
package com.itheima.d10_genericity_interface;
public class Teacher {
}
package com.itheima.d10_genericity_interface;
public class StudentData implements Data<Student>{
@Override
public void add(Student s) {
}
@Override
public void delete(int id) {
}
@Override
public void update(Student student) {
}
@Override
public Student queryById(int id) {
return null;
}
}
package com.itheima.d10_genericity_interface;
public class TeacherData implements Data<Teacher>{
@Override
public void add(Teacher s) {
}
@Override
public void delete(int id) {
}
@Override
public void update(Teacher teacher) {
}
@Override
public Teacher queryById(int id) {
return null;
}
}
(五)泛型通配符、上下限
1通配符:?
(1)?可以在“使用泛型”的时候代表一切类型
(2)E T K V 是在定义泛型的时候会使用的
2泛型通配符:案例导学
(1)开发一个极品飞车的游戏,所有的汽车都能一起参与比赛
注意:
(2)虽然BMW和BENZ都继承了Car但是ArrayList<BMW>和ArrayList<BENZ>与ArrayList<Car>没有关系的!!
3泛型的上下限:
(1)?extends Car:?必须是Car或者其子类 泛型上限
(2)?super Car:?必须是Car或者其父类 泛型下限
package com.itheima.d11_genericity_limit;
import java.util.ArrayList;
public class GenericDemo {
public static void main(String[] args) {
ArrayList<BENZ> benzs = new ArrayList<>();
benzs.add(new BENZ());
benzs.add(new BENZ());
benzs.add(new BENZ());
go(benzs);
ArrayList<BMW> bmw = new ArrayList<>();
bmw.add(new BMW());
bmw.add(new BMW());
bmw.add(new BMW());
/*ArrayList<Dog> dogs = new ArrayList<>();
dogs.add(new Dog());
dogs.add(new Dog());
dogs.add(new Dog());
go(dogs);*/
}
public static void go(ArrayList<? extends Car> cars){
}
}
class Dog{
}
class BENZ extends Car{
}
class BMW extends Car{
}
//父类
class Car{
}
教学视频资源
Java入门基础视频教程,java零基础自学首选黑马程序员Java入门教程(含Java项目和Java真题)_哔哩哔哩_bilibili