一. 对象数组的概述和使用
-
案例演示
- 需求: 创建5个学生对象, 将对象存入到数组中,遍历数组,打印学生信息
public static void main(String[] args) { Student[] sts = new Student[5]; sts[0] = new Student("小红", 18); sts[1] = new Student("小明", 19); sts[2] = new Student("小白", 20); sts[3] = new Student("小辉", 21); sts[4] = new Student("小张", 23); for (int i = 0; i < sts.length; i++) { System.out.println(sts[i]); } }
-
解析
- 数组中存放的是对象的地址值
- 遍历数组时就可以拿到引用地址值,调用对象完成方法
二. 集合概述
-
概述
- 我们都知道,数组的长度是不可变的, 当元素的个数超过数组的长度之后, 我们就只能通过创建长度更长的新数组的方式来存储元素, 太麻烦了
- 集合给我提供另外一种容器的概念,可变长度的容器, 这样,程序在使用的时候就不需要再考虑容器容量的问题,从而可以更加专心于业务
- 我们要知道,java中数组是唯一的底层容器,所有, 集合是开发者使用java规范制作的逻辑上的容器
-
数组和集合的区别
- 区别1
- 数组既可以存储基本数据类型, 又可以储存引用数据类型,基本数据类型存储的是值, 引用数据类型储存的是地址值
- 集合只能存储引用数据类型(对象的引用), 其实集合也可以存储基本数据类型, 但是在存储的时候自动装箱变成包装类对象
- 区别2
- 数组长度是固定的,不能自动增长
- 集合的长度的是可变的,可以根据元素的增加而增长
- 区别1
-
使用场景
- 如果元素的个数是固定的,推荐使用数组
- 如果元素的个数不固定,推荐使用集合(日常开发中,使用集合比较普遍)
-
集合体系图
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-xDjMyc2Y-1619488505722)(集合体系图.jpg)]
-
集合分类
- Collection集合
- 单列集合, 直接存储对象的引用
- Map集合
- 双列集合, 使用key-value的形式, 每个元素会有一个唯一的名称
- Collection集合
三. Collection集合
-
定义
- Collection是单列集合, 用于存储单个元素
- Collection是一个接口, 他的下面有多个子接口和实现类, 我们称之为Collection体系
-
分类
- List 集合中的元素是有序的,可以存放重复元素
- Queue 队列, 除优先级外, 保持先进先出的原则(基本不用)
- Set 集合中的元素是无序的, 不能存放重复的元素
-
体系图
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-9jOAUvXn-1619488505726)(Collection集合体系图.jpg)]
-
常用方法
- boolean add(E e) 添加元素
- boolean remove(Object o) 从此 collection 中移除指定元素的单个实例,如果存在的话
- void clear() 移除此 collection 中的所有元素
- boolean contains(Object o) 判断集合中是否包含指定元素
- boolean isEmpty() 判断集合中元素的个数是否为空
- int size() 获取集合中元素的个数
-
案例演示
public static void main(String[] args) { //如果没有泛型,会报出警告,不影响运行 Collection<Student> collection = new ArrayList<>(); Student student1 = new Student("小红", 18); Student student2 = new Student("小明", 19); collection.add(student1); //添加方法 collection.add(student2); //判断集合中是否包含某个元素 System.out.println(collection.contains(student1));//结果为 : true //判断集合中元素的个数是否为null System.out.println(collection.isEmpty());//结果: false //获取集合中元素的个数 System.out.println(collection.size());//结果为 : 2 //移除某个元素 System.out.println(collection.remove(student2));//结果:true System.out.println(collection.size());//结果: 1 //清空集合中的元素 collection.clear(); System.out.println(collection.size());//结果为0 }
-
集合中所有带All的方法
- boolean addAll(Collection c) 将指定 collection 中的所有元素都添加到此 collection 中
- boolean removeAll(Collection c) 移除此 collection 中那些也包含在指定 collection 中的所有元素
- boolean containsAll(Collection c) 如果此 collection 包含指定 collection 中的所有元素
- boolean retainAll(Collection c) 仅保留此 collection 中那些也包含在指定 collection 的元素
- 演示
public static void main(String[] args) { Collection<Student> collection = new ArrayList<>(); Student student1 = new Student("小红", 18); Student student2 = new Student("小明", 19); collection.add(student1); //添加方法 collection.add(student2); Collection<Student> collection2 = new ArrayList<>(); Student student3 = new Student("小辉", 18); collection2.add(student1); collection2.add(student3); //将collection2集合中的元素添加到collection集合中 collection.addAll(collection2); System.out.println(collection.size());//结果: 4 //判断collection集合中是否包含collection2集合中的所有元素 boolean flg = collection.containsAll(collection2); System.out.println(flg);//结果: true //仅在collection中保留两个集合中相同的元素 collection.retainAll(collection2); System.out.println(collection.size());//结果: 3 }
四. 迭代器
-
定义
- 集合是用来存储元素,存储的元素需要查看,那么就需要迭代(遍历)
-
案例演示遍历集合
public static void main(String[] args) { Collection<Student> collection = new ArrayList<>(); Student student1 = new Student("小红", 18); Student student2 = new Student("小明", 19); Student student3 = new Student("小辉", 18); collection.add(student1); //添加方法 collection.add(student2); collection.add(student3); //集合转数组进行遍历 Object[] obs= collection.toArray(); for (int i = 0; i < obs.length; i++) { System.out.println(obs[i]); //前提集合内的元素重写了toString()方法 } }
-
迭代器的遍历形式
- 步骤
- 获取迭代器
- 调用hashNext()方法判断下一个元素是否存在
- 调用next()方法获取元素
- 演示
public static void main(String[] args) { Collection<Student> collection = new ArrayList<>(); Student student1 = new Student("小红", 18); Student student2 = new Student("小明", 19); Student student3 = new Student("小辉", 18); collection.add(student1); //添加方法 collection.add(student2); collection.add(student3); //for循环的形式 for(Iterator<Student> it = collection.iterator();it.hasNext();){ Student student = it.next(); System.out.println(student); } //while循环的形式 Iterator<Student> it = collection.iterator(); while(it.hasNext()){ Student student = it.next(); System.out.println(student); } }
- 步骤
-
迭代器工作原理
- Iterator是一个接口,规定了迭代器的基本使用, 集合的子类都实现了迭代器方法, 同时返回属于自己的迭代器对象
- 迭代器相当于是集合的一个副本, 里面记录了集合的基本属性值.
- 使用时,我们先调用hashNext方法判断是否有下一个元素,如果有则返回true,否则返回false
- 然后调用next()方法,返回当前指针所在位置上的元素
-
修改集合导致的异常
- 当我们使用迭代器遍历集合的时候,如果对集合进行了修改,下一次循环会报错
- 原因: 集合会记录修改的次数, 如果迭代器发现集合副本和原集合修改次数不一样的话就会报错
- 解决办法: 使用迭代器的删除方法
- 演示
public static void main(String[] args) { Collection<Student> collection = new ArrayList<>(); Student student1 = new Student("小红", 18); Student student2 = new Student("小明", 19); collection.add(student1); //添加方法 collection.add(student2); //while循环的形式 Iterator<Student> it = collection.iterator(); while(it.hasNext()){ Student student = it.next(); //collection.remove(student); it.remove(); } }
五. List集合
- 定义
- List集合是有序的,可以储存重复的数据
- List集合通过记录元素在集合中的位置来准确的查找元素
- List集合体系
- ArrayList 底层使用数组(线程不安全)
- LinkedList 底层使用链表
- Vector 底层使用数组(线程安全的,不推荐使用)
六. ArrayList集合
-
定义
- 低层使用的是数组, 所以其特性非常接近于数组
- 储存的元素是有序的,而且可以重复存储, 通过数组角标来查询更改元素,速度非常快
- 由于每次增删都要改动数组中的角标,所有导致增删效率低下
-
ArrayList的增删改查原理
- ArrayList 集合初始化会有一个默认长度是10的数组, 内部还有一个记录当前元素个数的变量, 当储存的元素个数超过数组长度之后,容量就会扩充一半
- 当我们去查询集合中的元素时, 需要提供给集合一个角标值, 然后通过这个角标值查找集合中的元素
- 当我们去删除一个元素的时候, 集合就会根据角标删除这个元素,并且改动其他元素的位置,这就是导致增删缓慢的原因
- 其实如果我们是连续往集合尾部插入数据的话, 速度其实是非常快的, 因为其他元素的位置不需要改动,但是如果我们插入数据的位置是数组的前面或者中间,速度就会有明显的降低
-
构造方法
- ArrayList() 构造一个初始化容量为10的空列表
- ArrayList(Collection<? exends E> e) 构造一个包含执行集合元素的列表
- ArrayList(int initialCapacity) 构造一个具有指定初始容量的空列表
-
常用方法
- boolean add(E e) 将指定的元素添加到此列表的尾部
- void add(int index,E element) 将指定的元素插入此列表中的指定位置
- boolean contains(Object o) 如果此列表中包含指定的元素,则返回true
- E get(int index) 通过角标查找元素
- int indexOf(Object o) 返回此列表中首次出现的指定元素的索引, 或如果没有则返回 -1
- int lastIndexOf(Object o) 返回此列表中最后一次出现的指定元素的索引(从后先前查)没有返回-1
- boolean remove(Object o) 移除此列表中首次出现的指定元素(如果存在)
- E set(int index , E element) 用指定元素替代此列表中指定位置上的元素,返回原来的元素
- int size() 返回此列表中的元素数
-
演示
public static void main(String[] args) { ArrayList<String> list = new ArrayList<>(); //添加元素 list.add("小红"); list.add("小明"); //将元素添加到角标1上 list.add(1,"小辉"); System.out.println(list.contains("小明"));//true //通过角标获取 String str = list.get(1); System.out.println(str);//结果: 小辉 //通过元素获取角标 System.out.println(list.indexOf("小明"));//结果 : 2 //通过角标移除元素 System.out.println(list.remove(1));//结果: true //通过角标设置元素 System.out.println(list.set(1, "小李"));//小辉 }
-
ArrayList集合的遍历
- for 循环遍历, 基本上等同于数组
- 演示
public static void main(String[] args) { ArrayList<String> list = new ArrayList<>(); list.add("小红"); list.add("小明"); list.add("小辉"); for (int i = 0; i < list.size(); i++) { System.out.println(list.get(i)); } }
- 迭代器 使用公用迭代器
- 演示
public static void main(String[] args) { ArrayList<String> list = new ArrayList<>(); list.add("小红"); list.add("小明"); list.add("小辉"); Iterator<String> it = list.iterator(); while (it.hasNext()) { String str = it.next(); System.out.println(str); } }
- 迭代器2 List集合的迭代器(ListIterator) 可以从后往前遍历
- 演示
public static void main(String[] args) { ArrayList<String> list = new ArrayList<>(); list.add("小红"); list.add("小明"); list.add("小辉"); ListIterator<String> it = list.listIterator(); while (it.hasNext()) { String str = it.next(); System.out.println(str); } while(it.hasPrevious()){ String str = it.previous(); System.out.println(str); } }
-
测试题
- 去除集合中的重复字符串元素
- 演示
public static void main(String[] args) { ArrayList list = new ArrayList(); list.add("a"); list.add("b"); list.add("b"); list.add("b"); list.add("c"); list.add("c"); list.add("c"); list.add("c"); list.add("a"); System.out.println(list); ArrayList newList = getSingle(list); System.out.println(newList); }
七. LinkedList集合
-
定义
- 底层使用的是链表,就好像一条锁链
- 这个集合中的每个元素都被封装到一个叫Node的内部类中, 然后记录上一个元素和下一个元素的地址,通过手拉手形成一个链条
- 增删快, 查询慢
-
增删改查的原理
- 当需要去查询LinkedList集合中的元素时,需要从最开始的元素查找起,然后一层一层往后找,直到找到该元素,这样的动作十分消耗性能
- 当需要去删除元素的时候, 我们只需要将被删除元素两端的元素重新连接到一起,或者新增的时候将新元素和左右两边的元素连起来就可以了
-
构造方法
- LinkedList() 构造一个空列表
- LinkedList(Collection<? extends E> e) 构造一个包含指定collection中元素的列表
-
常用方法
- E remove() 获取并移除此列表的头
- E poll() 获取并移除此列表的头
- E peek() 获取但不移除此列表的头
-
演示
public static void main(String[] args) { LinkedList<String> list = new LinkedList<>(); list.add("小红"); list.add("小明"); list.add("小辉"); System.out.println(list.remove());//结果: 小红 System.out.println(list.size());//结果:2 System.out.println(list.poll());//结果: 小明 System.out.println(list.size());//结果:1 System.out.println(list.peek());//结果: 小辉 System.out.println(list.size());//结果:1 }
八. ArrayList, LinkedList 及Vector集合之间的区别
- 线程安全
- Vector : 线程安全
- ArrayList, LinkedList : 线程不安全
- 实现方式
- LinkedList : 链表
- ArrayList,Vector : 数组
- 扩容
- ArrayList和Vector使用数组实现, 当数组长度不够,内部会创建一个更大的数组
- LinkedList 不存在这方面的问题
- 速度
- ArrayList 查改块, 增删慢
- LinkedList 查改慢, 增删快
总结
-
集合
集合是一个容器
已经学过数组了, 数组也是容器,为什么今天还要学习集合呢?
数组使用起来太麻烦了 : 长度无法改变, 没有办法添加和删除
集合的长度动态的, 有增删改查的方法, 使用起来非常方便
-
集合的体系
Collection : 单列集合 一个位置上存一个元素
- List : 有序 可以存储重复元素
- ArrayList
- LinkedList
- Set : 无序, 不能存储重复元素
Map : 双列集合
- List : 有序 可以存储重复元素
-
LIst集合的常用功能
add(E) add(index,E) remove(index) remove(E) set(E) get(index)
indexOf(E) lastIndexOf(E) clear() contains(E) size() isEmpty()
addAll(Colleaction) removeAll(Colleaction) containsAll(Colleaction) retainAll(Colleaction)
-
ArrayList
ArrayList() ArrayList(capacity) ArrayList(Colleaction)
底层数组, 需要扩容 , 增删效率低 查改效率高 ,线程不安全
-
LinkedList
ArrayList() ArrayList(Colleaction)
底层链表 , 不需要扩容 , 增删效率高 查改效率低, 线程不安全
-
迭代器
用于遍历集合
有些集合是没有角标的的, 无法使用for循环来遍历
工作原理: 一个指针不断的往下移动
使用方法 : hasNext() next();
作业
-
第一个题
- 需求: 定义一个swap()方法,传入集合和两个角标,将两个角标上的元素交换位置
-
第二题
- 需求: 创建一个Student类,定义name和age属性,创建几个Student对象放入集合中,遍历集合,查找年龄最大的对象,并打印
-
第三题
- 需求: 定义集合让集合中添加多个元素,然后将集合中的元素位置反转
-
第四题
- 需求: 创建一个Student类,定义name和age属性, 创建几个对象存入集合中(有重复属性的对象),创建方法去除集合中的重复元素
-
扩展题
-
第一题
- 需求: 现在有16只球队, 科特迪瓦,阿根廷,澳大利亚,塞尔维亚,荷兰,尼日利亚,日本,美国,中国,新西兰,巴西,比利时,韩国,喀麦隆,洪都拉斯,意大利. 将这16只球队存入到集合中,然后随机分成4组存入到4个集合中.遍历打印集合
-
第二题
- 需求: 创建一个Student类, 定义 姓名,年龄,班级,成绩 属性, 然后创建多个对象存入集合中, 求出所有学生的平均年龄和每个班级的平均成绩
- Student类的属性如下所示
private String name; private int age; private int score; private String ClassNum;
-