集合和数组都是容器
数组定义完成并启动后,类型确定,长度固定
在进行增删数据操作的时候,数组是不太合适的,增删数据都需要放弃原有数组或者移位
数组适合的场景,当业务数据的个数是固定的,且都是同一批数据类型的时候,可以采取定义数组存储
集合是java中存储对象数据的一种容器
集合的大小不固定,启动后可以动态变化,类型也可以选择不固定,集合更像气球
集合非常适合做元素的增删操作
注意:集合中只能存储引用数据类型,如果要存储基本类型数据可以选用包装类
数组和集合的元素存储的个数问题
数组定义后类型确定,长度固定
集合类型可以不固定,大小是可变的
数组和集合存储元素的类型问题
数组可以存储基本类型和引用类型的数据
集合只能存储引用数据类型的数据
数组和集合适合的场景
数组适合做数据个数和类型确定的场景
集合适合做数据个数不确定,且要做增删元素的场景
注意:前期先掌握Collection集合体系的使用
Collection集合特点
List系列集合:添加的元素是有序,可重复,有索引
ArryList、LinekdList:有序,可重复,有索引
Set系列集合:添加的元素是无需,不重复,无索引
HashSet:无序,不重复,无索引:LinkedHashSet:有序、不重复、五索引
TreeSet:按照大小默认升序排序,不重复,无索引
package com.itheima.d1_collection; import java.util.ArrayList; import java.util.Collection; public class CollectionDemo1 { public static void main(String[] args) { //有序 可重复 有索引 Collection list=new ArrayList(); list.add("Java"); list.add("Java"); list.add("Mybatis"); list.add(23); list.add(23); System.out.println(list); } } 集合的代表是?
Collection接口
Collection集合分了哪2大常用的集合体系?
list系列集合:添加的元素是有序、可重复、有索引
Set系列集合:添加的元素是无需、不重复、无索引
如何约定集合存储数据的类型,需要注意什么?
集合支持泛型
集合和泛型不支持基本类型,只支持引用数据类型
Collection集合常用API
Collection是单列集合的祖宗接口,它的功能是全部单列集合都可以继承使用的
Collection API如下:
package com.itheima.d1_collection; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; public class CollectionDemo { public static void main(String[] args) { //HashSet:添加的元素时无需,不重复,无索引 Collection<String> list=new ArrayList<>(); //1.添加元素,添加成功返回true list.add("Java"); list.add("HTML"); list.add("HTML"); System.out.println(list.add("黑马")); System.out.println(list); //2.清空集合的元素 //list.clear(); //System.out.println(list); //3.判断集合是否为空,是空返回true System.out.println(list.isEmpty()); //4.获取集合的大小 System.out.println(list.size()); //5.判断集合中是否包含某个元素 System.out.println(list.contains("Java")); System.out.println(list.contains("黑")); //6.删除某个元素:如果有多个重复元素默认删除前面的第一个 list.remove("Java"); System.out.println(list); //7.把集合转换成数据[Java,独孤求败,HTML,Mybatis] Object[] arrs=list.toArray(); System.out.println("数组:"+ Arrays.toString(arrs)); System.out.println("----------拓展--------"); Collection<String> c1=new ArrayList<>(); c1.add("Java"); c1.add("java1"); Collection<String> c2=new ArrayList<>(); c2.add("赵敏"); c2.add("殷素素"); c1.addAll(c2); System.out.println(c1); } }
Collection迭代器遍历集合:
遍历就是一个一个的把容器中的元素访问一遍
迭代器在Java中的代表是Iterator,迭代器是集合的专用遍历方式
Collection集合获取迭代器
Iterator<E> iterator() 返回集合中的迭代器对象,该迭代器对象默认指向当前集合的0索引
boolean hashNext() 询问当前位置是否有元素存在,存在返回true,不存在返回false
E next() 获取当前位置的元素,并同时将迭代器对象移向下一个位置,注意防止去除越界
package com.itheima.d1_collection; import java.util.ArrayList; import java.util.Collection; import java.util.Iterator; public class CollectionDemo3 { public static void main(String[] args) { Collection<String> lists = new ArrayList<>(); lists.add("赵敏"); lists.add("小明"); lists.add("索索"); System.out.println(lists); //根据当前集合的迭代器对象 Iterator<String> iterator = lists.iterator(); while(iterator.hasNext()){ String ele= iterator.next(); System.out.println(ele); } System.out.println("--------------"); } }
增强for循环
增强for循环:既可以遍历集合也可以遍历数组
它是JDK5之后出现的,其内部原理是一个Iterator迭代器,遍历集合相当于是迭代器的简化写法
实现Iterable接口的类才可以使用迭代器和增强for,Collection接口已经实现了Iterable接口
格式:
for(元素数据类型 变量名:数组或者Collection集合){
}
增强for可以遍历哪些容器?
既可以遍历集合也可以遍历数据
增强for的关键是记住它的遍历格式
for(元素数据类型 变量名:数组或者Collection集合){
//在此处使用变量即可,该变量就是元素
}
方式三:lambda表达式
lambda表达式:得益于JDK 8开始的新技术Lambda
package com.itheima.d1_collection; import java.util.ArrayList; import java.util.Collection; import java.util.function.Consumer; public class CollectionDemo5 { public static void main(String[] args) { Collection<String> lists = new ArrayList<>(); 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集合存储自定义类型的对象
package com.itheima.d1_collection; public class Movies { private String name; private double money; private String actor; public Movies() { } public Movies(String name, double money, String actor) { this.name = name; this.money = money; this.actor = actor; } public String getName() { return name; } public void setName(String name) { this.name = name; } public double getMoney() { return money; } public void setMoney(double money) { this.money = money; } public String getActor() { return actor; } public void setActor(String actor) { this.actor = actor; } @Override public String toString() { return "Movies{" + "name='" + name + '\'' + ", money=" + money + ", actor='" + actor + '\'' + '}'; } }
package com.itheima.d1_collection; import java.util.ArrayList; import java.util.Collection; public class TestDemo { //1.定义一个电影类 //2.定义一个集合对象存储3部电影对象 public static void main(String[] args) { Collection<Movies> movies=new ArrayList<>(); movies.add(new Movies("<你好,李焕英>",9.6,"张晓菲,贾玲")); movies.add(new Movies("<唐人街探案>",8.5,"王宝强,刘昊然")); movies.add(new Movies("<刺杀小说家>",8.9,"袁洁莹,杨幂")); //3.遍历集合容器中的每个电影对象 for (Movies movie:movies) { System.out.println("片名:"+movie.getName()); System.out.println("得分:"+movie.getMoney()); System.out.println("主演:"+movie.getActor()); } } }
集合中存储的元素是什么信息?
集合中存储的是元素对象的地址
常见数据结构
数据结构概述、栈、队列
数据结构是计算机底层存储,组织数据的方式。是指数据相互之间是以什么方式排列在一起的
通常情况下,精心选择的数据结构可以带来更高的运行或者存储效率
常见的数据结构
栈 队列 数组 链表 二叉树 二叉查找树 平衡二叉树 红黑树
栈数据结构的执行特点
后进后出,先进先出
常见数据结构队列
先进先出,后进后出
数组:
常见数据结构之数组:
查询速度快:查询数据通过地址值和索引定位,查询任意数据耗时相同(元素在内存中是连续存储的)
删除效率低:要将原始数据删除,同时后面每个数据前移
添加效率极低:添加位置后每个数据后移,再添加元素
链表:
链表中的元素是在内存中不连续存储的,每个元素节点包含数据值和下一个元素的地址
链表中的元素是游离存储的,每个元素节点包含数据值和下一个元素的地址
链表查询慢,无论查询哪个数据都要从头开始找
链表增删相对比较快
在数据AC之间添加一个数据B
1.数据B对应的下一个数据地址指向数据C
2.数据A对应的下一个数据地址指向数据B
删除数据BD之间的数据C
1.数据B对应的下一个数据地址指向数据D
2.数据C删除
二叉树概述:
二叉树的特点:
普通二叉树
二叉查找树 又称二叉排序树或者二叉搜索树
特点:
1.每一个节点上最多有两个子节点
2.左子树上所有节点的值都小于根节点的值 目的:提高检索数据的性能
3.右子树上所有节点的值都大于根节点的值
二叉树查找树添节点
二叉树查找存在的问题:
出现瘸子现象:导致查询的性能与单链表一样,查询速度变慢
数据结构-平衡二叉树
平衡二叉树是在满足查找二叉树的大小规则下,让书尽可能矮小,一次提高数据的性能
平衡二叉树的要求:
任意节点的左右两个子树的高度差不超过1,任意节点的左右两个子树都是一棵平衡二叉树
红黑树
红黑树是一种自平衡的二叉查找树,是计算机科学中用到的一种数据结构
1972年出现,当时被称之为平衡二叉B树。1978年被修改为如今的"红黑树"
每一个节点可以是红或者黑:红黑树不是通过高度平衡的,它的平衡是通过"红黑规则"进行实现的
红黑规则:
每一个节点或是红色的,或者是黑色的,根节点必须是黑色
如果一个节点没有子节点或者父节点,则该节点对应的指针属性值为null,这些Nil视为叶节点,叶节点是黑色的
如果某一个节点是红色,那么它的字节点必须是黑色(不能出现两个红色节点项链的情况)
对每一个节点,从该节点到其所有后代叶节点的简单路径上,均包含相同数目的黑色节点
添加节点:
添加的节点的颜色,可以是红色的,也可以是黑色的
默认用红色效率高
各种数据结构的特点和作用是什么样的?
队列:先进先出,后进后出
栈:后进先出,先进后出
数组:内存连续区域,查询快,增删慢
链表:元素是游离的,查询慢,首尾操作极快
二叉树:永远只有一个根结点,每个结点不超过2个子节点的树
查找二叉树:小的左边,大的右边,但是可能树很高,查询性能变差
平衡查找二叉树:让书的高度差不大于1,增删改查都提高了
红黑树(就是基于红黑规则实现了自平衡的排序二叉树)
List系列集合
List集合特点、独有API
ArrayList、LinekdList:有序,可重复,有索引
List系列集合特点:
ArrayList、LinekdList:有序,可重复,有索引
List的实现类的底层原理:
ArrayList底层是基于数组实现的,根据查询元素快,增删相对慢
LinkedList底层是基于双链表实现的,查询元素慢,增删首位元素是非常快的
List系列集合特点:
ArrayList、LinkdList:有序,可重复,有索引
List的实现类的底层原理:
ArrayList底层是基于数组实现的,根据查询元素快,增删相对慢
LinkedList底层基于双链表实现的,查询元素慢,增删首尾元素是非常快的
package com.itheima.d1_collection; import java.util.ArrayList; import java.util.Iterator; import java.util.List; public class TestDemo1 { public static void main(String[] args) { List<String> lists = new ArrayList<>(); lists.add("java1"); lists.add("java2"); lists.add("java3"); System.out.println("-------------"); //1.for循环 for (int i = 0; i < lists.size(); i++) { String ele=lists.get(i); System.out.println(ele); } System.out.println("----------------"); //2.foreach for(String ele:lists){ System.out.println(ele); } //3.迭代器 System.out.println("-------------------"); Iterator<String> iterator = lists.iterator(); while(iterator.hasNext()){ String ele=iterator.next(); System.out.println(ele); } //4.JDK1.8开始之后的lambda表达式 System.out.println("---------------------"); lists.forEach(s->{ System.out.println(s); }); } }
package com.itheima.d1_collection; import java.util.LinkedList; public class ListDemo3 { public static void main(String[] args) { LinkedList<String> stack=new LinkedList<>(); stack.addFirst("第一颗子弹"); stack.addFirst("第二课"); stack.addFirst("第三颗子弹"); System.out.println(stack); //出栈,弹栈 System.out.println(stack.removeFirst()); System.out.println(stack.removeFirst()); System.out.println(stack.removeFirst()); //队列 LinkedList<String> queue=new LinkedList<>(); queue.addLast("1号"); queue.addLast("2号"); queue.addLast("3号"); System.out.println(queue); } }
package com.itheima.d1_collection; import java.util.ArrayList; import java.util.Iterator; import java.util.List; public class Test { public static void main(String[] args) { List<String> list = new ArrayList<>(); list.add("黑马"); list.add("Java"); list.add("赵敏"); list.add("素素"); System.out.println(list); //迭代器遍历删除 /*Iterator<String> iterator = list.iterator(); while(iterator.hasNext()){ String ele = iterator.next(); if("Java".equals(ele)){ //list.remove("Java");会报错 iterator.remove();//使用迭代器删除当前位置的元素,保证不后移,能成功遍历到全部元素 } } System.out.println(list);*/ //foreach遍历删除 /*for (String s: list) { if("Java".equals(s)){ list.remove("Java"); } }*/ //Lambda表达式 会出现bug /*list.forEach(s -> { if("Java".equals(s)){ list.remove("Java"); } });*/ //解决方案: //for循环 /*for (int i = list.size()-1; i >=0; i--) { String ele=list.get(i); if("Java".equals(ele)){ list.remove("Java"); } }*/ for (int i = 0; i < list.size()-1; i++) { String ele=list.get(i); if("Java".equals(ele)){ list.remove("Java"); i--; } } System.out.println(list); } }
泛型深入:
泛型的概述和优势:
泛型:是JDK5中引入的特性,可以在编译阶段约束操作的数据类型,并进行检查
泛型的格式:<数据类型> 注意:泛型只能支持引用数据类型
集合体系的的全部接口和实现类都是支持泛型的使用的
泛型的好处:
统一数据类型
把运行时期的问题提前到了编译期间,避免了强制类型转换可能出现的异常,因为编译阶段类型就能确定下来
泛型类的概述
定义类同时定义了泛型的类就是泛型类
泛型类的格式:修饰符 class 类名<泛型变量>{ }
范例:public class MrArrayList<T>{}
此处泛型变量T可以随便写为任意标识,常见的如E、T、K、V等
作用:编译阶段可以指定数据类型,类似于集合的作用
泛型类的原理:
把出现泛型变量的地方全部替换成传输的真实数据类型
泛型类的核心思想:
把出现泛型变量的地方全部替换成传输的真实数据类型
泛型类的作用:
编译阶段约定操作的数据的类型,类似于集合的作用
泛型类的核心思想:
把出现泛型变量的地方全部替换成传输的真实数据类型
泛型类的作用:
编译阶段约定操作的数据的类型,类似于集合的作用
泛型方法的概述:
定义方法时同时定义了泛型的方法就是泛型方法
泛型方法的方式:修饰符<泛型变量> 方法返回值 方法名称(形参列表){ }
范例:public <T> void show(T t){ }
作用:方法中可以使用泛型接受一切实际类型的参数,方法更具备通用性
任何类型的数组,都能返回它的内容。也就时实现Arrays.toString(数组)的功能
package com.itheima.d8_generikity; public class Test { public static void main(String[] args) { String[] names={"小路","蓉蓉","小文"}; printArray(names); } public static <T> void printArray(T[] arr){ if(arr != null){ StringBuilder sb=new StringBuilder("["); for (int i = 0; i < arr.length; i++) { sb.append(arr[i]).append(i==arr.length-1?"":","); } sb.append("]"); System.out.println(sb); }else{ System.out.println(arr); } } }
泛型方法的核心思想
把出现泛型变量的地方全部替换成传输的真实数据类型
泛型方法的做用:
方法中可以使用泛型接收一切实际类型的参数,方法更具备通用性
泛型接口可以约束实现类,实现类可以在实现接口的时候传入自己操作的数据这样重写的方法都将是针对于该类型的操作
通配符:?
?可以在"使用泛型"的时候代表一切类型
E T K V是在定义泛型的时候使用的
? extends Car: ?必须是Car或者其子类,泛型上限
? extends Car: ? 必须是Car或者其父类,泛型下限