呼~,历过好几天的奋战终于把集合框架肝完了,b站某马老师讲的是真的非常详细而且动听,原理给你分析得明明白白的,此前也找了许多关于集合这一大章节的视频,发现更多的是针对于使用,原理讲的并不是很多,这就导致我在练习或者回顾时还是一知半解。以下是我结合视频以及个人的一些理解和体会做的笔记总结。路漫漫其修远兮,吾将上下而求索,希望这篇总结对你有些许帮助,嘻嘻!
1.1集合概述:
集合:Java中提供的一种容器,可以用来存储多个数据。java集合大致可以分为Set,List,Queue和Map四种体系。
数组和集合的区别:
-
数组的长度是固定的。集合的长度是可变的。
-
数组存储的是同一类型的数据,可以存储基本数据类型值。容器能存储对象,而且存储对象的类型可以不一致。在开发中当对象多的时候,使用容器进行存储。
1.2集合架构
单列集合体系结构:
Collection接口是所有单列集合的父接口,因此在单列集合中定义的List和set通用的一些方法,这些方法可以操作所有的单列集合。方法如下:
1.3Collection集合常用方法
-
public boolean add(E e); 向集合中添加元素
-
public boolean remove(E e); 删除集合中的某个元素
-
public void clear(); 清空集合中所有的元素
-
public boolean contains(); 判断集合中是否含有xxx元素
-
publicboolean isEmpty(); 判断集合是否为空
-
publicint size(); 计算集合的长度
-
public Object[] toArray(); 将集合转成一个数组
【参考代码】
package Collection;
?
import java.util.ArrayList;
import java.util.Collection;
?
/*
Collection集合常用方法
boolean add(E e); 向集合中添加元素
boolean remove(E e); 删除集合中的某个元素
void clear(); 清空集合中所有的元素
boolean contains(); 判断集合中是否含有xxx元素
boolean isEmpty(); 判断集合是否为空
int size(); 计算集合的长度
Object[] toArray(); 将集合转成一个数组
*/
public class Test {
public static void main(String[] args) {
//创建集合对象 , 可以多态使用
Collection<String>col = new ArrayList<>();
// Collection<String>col = new HashSet<>(); 下面的功能照样能实现:共性方法
col.add("小明"); // 添加元素
col.add("小红");
col.add("小蓝");
col.add("小绿");
System.out.println(col); //[小明, 小红, 小蓝, 小绿]
?
//boolean remove(E e); 删除集合中的某个元素
// boolean ans = col.remove("小明");
// System.out.println(ans);//true
// System.out.println(col);//[小红, 小蓝, 小绿]
?
//void clear(); 清空集合中所有的元素
// col.clear();
// System.out.println(col);//[]
?
//boolean contains(); 判断集合中是否含有xxx元素
// boolean result = col.contains("小明");
// System.out.println(result);//true
?
//boolean isEmpty(); 判断集合是否为空
// boolean result = col.isEmpty();
// System.out.println(result);// 不为空false
?
//int size(); 计算集合的长度
// int len = col.size();
// System.out.println(len);// 4
?
//Object[] toArray(); 将集合转成一个数组
Object[] arr = col.toArray();
// 遍历数组
// for (int i = 0; i < arr.length; i++) {
// System.out.println(arr[i]);
// }
}
}
二:迭代器Iterator
引入:由于集合有多种,每种集合存储跟读取的方式都不一样,好比衣柜、水瓶、药瓶,你存和取的方式肯定不一样。如果每种集合都定义一种遍历方式那将十分的繁琐。
迭代器(Iterator):它不是一个容器而是接口,它是一种用于访问容器的方法,可用于迭代 List、Set和Map等容器。
迭代:即Collection集合的通用获取方式。再获取元素之前先要判断集合中是否有元素,如果有就将这个元素去取出来,继续再判断,直到集合所有元素被取出来为止。即:一个一个的往外拿。
作用:帮我们遍历或者拿到容器里边的数据。
2.1Iterator接口
迭代器常用操作:
-
next() 下一个
-
hasNext() 判断是否存在下一个元素
-
remove() 删除元素
迭代器的使用步骤:
-
使用集合中的的方法iterator()获取迭代器的实现类对象,使用Iterator接口接收(多态)
-
使用Tterator接口中的方法hashnext()判断还有没有下一个元素
-
使用Tterator接口中的方法next()取出集合的下一个元素
【参考代码】
package Iterator;
?
import javax.swing.text.html.parser.Entity;
import java.util.*;
?
public class Test {
public static void main(String[] args) {
//创建一个集合对象
Collection<String>col = new ArrayList();
//添加元素
col.add("小明");
col.add("小红");
col.add("小蓝");
col.add("小绿");
?
/*
1.使用集合的方法iterator()获取迭代器的实现类对象,使用Iterator接口接收(多态)
注意:
Iterator接口也是有泛型的,迭代器的泛型跟集合走,集合是什么泛型,迭代器就是什么泛型
*/
// 多态 接口 实现类对象
Iterator<String>it = col.iterator();
?
// 2.使用 Iterator接口中的hashNext方法判断是否还有下一个元素
while(it.hasNext());{
// 3.使用 Iterator接口中的next方法取出集合的下一个元素
String str = it.next();
System.out.println(str);
}
?
}
}
2.2Iterator的实现原理:
2.3增强for()
增强for循环(for each循环)是JDk1.5之后的一个高循环,专门用来遍历数组和集合的,所有的数组跟单列集合都可以使用。它的内部原理就是一个迭代器Iterator,所以在遍历过程中,不能对集合元素进行增删操作。
语法:
for(类型 变量 : 数组/集合){// 数组或者集合里的每一项赋值给这个变量
// 循环体
}
【参考代码】
String[] student = {"小明","小红","小蓝"};
// // 传统遍历方式
// for (int i = 0; i < student.length; i++) {
// System.out.println(student[i]);
// }
?
// 增强for
for(String c : student){
System.out.println(c);
}
?
--------------------------------
List<Integer>list = new ArrayList<Integer>();
list.add(123);
list.add(234);
list.add(456);
for(Integer n : list){
System.out.println(n);
}
注:增强for必须有被遍历的目标。目标只能是数组或者Collection,而它仅仅作为遍历操作实现
2.4迭代器注意事项
-
迭代器是一次性对象。我们不能重置迭代器,它不能被重用。
-
要再次遍历同一集合的元素,请通过调用集合的iterator()方法来创建一个新的Iterator。
三:泛型
3.1泛型概述
在前面学习集合时,我们知道集合时可以存放任意对象的,只要把对象存储集合后,它们都会被向上转型提升为Object类型。当我们要取出这些对象时必须进行类型强制转换,由Object类型变为原来的类型。
3.2泛型的优缺点
不使用泛型:
- 好处:集合默认类型是Object类,可以存储任意类型的数据
- 弊端:不安全,会引发异常,需要强转。
public static void main(String[] args) {
List list = new ArrayList();
list.add("小明");
list.add("小红");
for (int i = 0; i < list.size(); i++) {
String s= (String)list.get(i) // 强转
System.out.println(s);
}
}
?
使用泛型:
-
好处:避免了类型强制转化的麻烦,存的什么类型,取出来的也是什么类型;代码运行之后才会抛出异常,写代码时不会报错
-
弊端:泛型是什么类型只能存储什么类型的数据。
public static void main(String[] args) {
List<String> list = new ArrayList();// 规范了数据类型,只能放字符串!
list.add("小明");
list.add("小红");
//stringList.add(123);// 除了字符串以外的类型不能加,报错!
for (int i = 0; i < list.size(); i++) {
String s = list.get(i); // 不用再强转了
System.out.println(s);
}
}
?
在上述的实例中,我们只能添加String类型的数据,否则编译器会报错。
3.3泛型的定义与使用
泛型类
定义格式:
修饰符 class 类名<泛型变量>{
?
}
// 注:泛型变量建议使用E、T、K、V
例如:
public class Box<T> {
private T t;
public void add(T t) {
this.t = t;
}
public T get() {
return t;
}
参考示例:
注:在创建对象时确定泛型的类型
泛型方法
定义格式:
修饰符 <泛型变量> 返回值的类型 方法名称(形参列表){
//方法体
}
注:含有泛型的方法,在调用的时候确定泛型的数据类型
传递什么类型的参数,泛型就是什么类型
参考示例:
泛型接口
定义格式:
public interface 接口名<泛型类型> {
}
使用方式1:定义接口的实现类,实现接口,并且指定接口的泛型
使用方式2:接口使用什么泛型,实现类就使用什么泛型,类跟着接口走。
就相当于定义了一个含有泛型的类,创建对象的时候确定泛型的类型。
下图接口同上图接口
3.4泛型的通配符
当使用泛型类或接口时,传递数据中,泛型类型不确定,可以通过通配符表示<?>表示。但一旦使用泛型的通配符后,只能使用Object类中的共性方法,集合中元素自身方法无法使用。
通配符的基本使用
泛型的通配符:不知道使用什么类型来接收的时候,此时可以使用 ? ,?表示未知通配符
此时只能接收数据,不能往集合中存储数据。
【参考代码】
package FanXing;
?
import javax.swing.text.html.HTMLDocument;
import java.util.ArrayList;
import java.util.Iterator;
/*
泛型的通配符:
?:代表数据类型
使用方式:
不能在创建对象时使用
只能作为方法的传递参数使用
*/
public class Generic {
public static void main(String[] args) {
?
ArrayList<Integer>list01 = new ArrayList<>();
list01.add(123);
list01.add(456);
?
ArrayList<String>list02 = new ArrayList<>();
list02.add("小明");
list02.add("小红");
// ......还有很多其它类型
printArray(list01);
printArray(list02);
/*
定义一个方法,能遍历所有类型的ArrayList集合
这时候我们不知道ArrayList集合使用的是什么类型,可以使用泛型的通配符:?来代表数据类型
注意:泛型没有继承的概念
*/
}
?
public static void printArray(ArrayList<?>list){
// 使用迭代器遍历集合
Iterator<?> it = list.iterator();
while(it.hasNext()){
Object obj = it.next();//it.next()取出的元素是Object类。Object类 可以接收任意的数据类型
System.out.println(obj);
}
?
}
}
通配符高级使用-----受限泛型
之前设置泛型的时候,实际上是可以可以任意设置的,只要是类就可以设置。但在Java的泛型中可以指定一个泛型的上限和下限。
泛型的上限:
-
格式:类型名称<? extends E >对象名称 代表的泛型只能是E类型的子类/本身
-
意义:只能接收该类型及其子集
泛型的下限:
-
格式:类型名称<? super E >对象名称 代表的泛型只能是E类型的父类/本身
-
意义:只能接收该类型及其父类
比如:Object类、String类、Number类、Integer类,其中Number类是Integer的父类。
四:Java常见数据结构
集合是基于数据结构做出来的,不同的集合底层采用不同的数据结构。不同的数据结构,功能和作用是不一样的。
数据结构是指数据以什么方式组织在一起。不同的数据结构,增删查的性能是不一样的。
41栈
栈:stack,又称堆栈,它是运算受限的线性表,只能在栈的受限一端进行插入和删除操作。
特点:先进后出
4.2队列
队列:queue,简称队,它同栈由于也是运算受限的线性表,只能在表的一端进行插入操作,而在表的另一端进行删除操作。
特点:先进先出
4.3数组
数组:Array,是个有序的元素序列,数组在内存中开辟一段连续的空间。
特点:
-
查询快:随机存取,通过索引可以快速访问元素
-
增删慢:静态分配内存,数组的长度是固定,存在空间闲置或者溢出现象;不适合进行插入和删除操作,需要移动大量元素。
4.4链表
链表:linked list,由一系列结点node组成,结点可以在运行时动态产生。每个节点包含两个部分:数据域(data)和指向下一个节点的指针域(next)。链表包括单链表和双向链表。
-
单链表:链表中只有一条链子,不能保证元素的顺序(存储和取出的顺序可能不一致)
-
双向链表:链表中只有两条链子,有一条链子专门记录元素的顺序,是一个有序的集合。
特点:
-
查询慢:链表的地址不是连续的,每次查询都要从头到尾进行遍历。
-
增删快:动态分派内存,增/删一个节点对于链表整体结构没有影响,增删操作效率高。
4.5红黑树
红黑树:R-B Tree,全称是Red-Black Tree,又称为“红黑树”,它一种特殊的二叉查找树。红黑树的每个节点上都有存储位表示节点的颜色,可以是红(Red)或黑(Black),它是一种弱平衡二叉树(Weak AVL)。
特点:
(1)每个节点或者是黑色,或者是红色。 (2)根节点是黑色。 (3)每个叶子节点(NIL)是黑色。 [注意:这里叶子节点,是指为空(NIL或NULL)的叶子节点!] (4)如果一个节点是红色的,则它的子节点必须是黑色的。 (5)从一个节点到该节点的子孙节点的所有路径上包含相同数目的黑节点。
注:以上数据结构可以结合所学过c语言数据结构
五:List集合体系
5.1List概述
List集合体系:添加元素,是有序,可重复,有索引的,大小可变。实际开发中常用的是ArrayList集合。List集合体系包括以下几种:
-
ArrayList——添加元素,是有序,可重复,有索引的。
-
LinkedList——添加元素,是有序,可重复,有索引的。
-
Vector——查询快,增删慢;运行效率慢、线程安全
List集合继承了Collection集合的全部功能,同时因为List集合系列有索引,所以多了很多按照索引操作元素的方法:
add(int index, E element) 根据索引添加元素
get(int index) 根据索引获取元素
remove(int index) 根据索引删除元素
set(int index, E element) 根据索引修改该位置上的元素
contains(E element)判断容器是否含有XXX东西
clear() 清空集合中的元素
size()计算集合的大小
【参考代码】
package Collection;
?
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
?
public class TestList {
public static void main(String[] args) {
List<String>list = new ArrayList();
// 换成Linkedist 下面的操作都能一样实现
?
list.add("小明");
list.add("小红");
list.add("小蓝");
list.add("小绿");
list.add("小明");
?
?
// // 在某个索引位置往集合中添加元素
// list.add(2,"哈哈哈哈");
// System.out.println(list);
?
// // 删除集合中某个元素
// list.remove("小蓝");
?
?
// // 根据索引获取元素
// System.out.println(list.get(0));
?
// // 修改索引位置处的元素
// list.set(0,"小明很明白!");
// System.out.println(list.get(0));//小明很明白!
?
// // 计算列表的大小(长度):
// System.out.println(list.size());
?
// //判断列表中是否有xxx false
// System.out.println(list.contains("小蓝"));
?
}
}
5.2List遍历方式
-
for循环
// 遍历列表
for (int i = 0; i < list.size(); i++) {
String str = list.get(i);
System.out.println(str);
?
} -
迭代器
Iterator<String>it = list.iterator(); // 创建一个List的迭代器
?
while(it.hasNext()){// 判断有没有下一个元素
String s = it.next();
System.out.println(s);
} -
增强for
List<String>list = new ArrayList<>();
?
for(String s : list){
System.out.println(s);
} -
Lambda表达式(了解)
list.foreach(s -> {
System.out.println(s);
});
5.3ArrayList集合
ArrayList集合存储的结构是数组结构,元素增删慢,查询快。最常用。
5.4LinkedList集合
LinkedList集合存储的结构是链表结构,方便元素的添加、删除操作。LinkedList是一个双向链表
LinkedList的特点:
-
底层是一个链表结构:查询慢,增删快
-
里边含有大量操作首尾元素的方法
-
注:使用LinkedList集合特有的方法,不能使用多态,命名要注意了!
实际开发中对一个集合的添加、删除操作经常涉及首尾操作,LinkedList提供了很多操作首尾元素方法
public void addFirst(E e); 将指定的元素插到列表开头。
public void addLat(E e); 将指定的元素插到列表结尾。 此方法等效于add()方法
public void push(E e); 将元素推入此列表所示的堆栈。 此方法等效于addFirst()方法
?
public E getFirst(); 返回此列表的第一个元素
public E getLast(); 返回此列表的最后一个元素
?
public E removeFirst(); 移除并返回此列表的第一个元素
public E removeLast(); 移除并返回此列表的最后一个元素
public E pop(E e); 入此列表所示的堆栈中弹出一个元素。
?
public boolean isEmpty(); 如果列表为空 返回true
【参考代码】
package Collection;
/*
public void addFirst(E e); 将指定的元素插到列表开头。
public void addLast(E e); 将指定的元素插到列表结尾。
public void push(E e); 将元素推入此列表所示的堆栈。
?
public E getFrist(); 返回此列表的第一个元素
public E getLast(); 返回此列表的最后一个元素
?
public E removeFrist(); 移除并返回此列表的第一个元素
public E removeLast(); 移除并返回此列表的最后一个元素
public E pop(E e); 入此列表所示的堆栈中弹出一个元素。
?
public boolean isEmpty(); 如果列表为空 返回true
*/
?
import java.util.LinkedList;
import java.util.List;
?
public class TestLinkedList {
public static void main(String[] args) {
show01();
show02();
show03();
}
?
/*
public void addFirst(E e); 将指定的元素插到列表开头。
public void addLast(E e); 将指定的元素插到列表结尾。
public void push(E e); 将元素推入此列表所示的堆栈
*/
public static void show01(){
// 注:LinkedList特有的方法不能使用多态!
// List<String> list = new LinkedList<>(); 是不对的
LinkedList<String>list = new LinkedList<>();
?
// add()添加元素
list.add("a");
list.add("b");
list.add("c");
System.out.println(list);//[a, b, c]
?
list.addFirst("hhh");
//public void push(E e); 将元素推入此列表所示的堆栈。 等效于addFirst()
list.push("hhh");
System.out.println(list);
?
//public void lastFrist(E e); 将指定的元素插到列表结尾。 等效于add()
list.addLast("com");
System.out.println(list);
?
}
/*
public E getFrist(); 返回此列表的第一个元素
public E getLast(); 返回此列表的最后一个元素
*/
public static void show02(){
LinkedList<String>list = new LinkedList<>();
// add()添加元素
list.add("a");
list.add("b");
list.add("c");
// list.clear(); // 清空集合中所有元素
if(! list.isEmpty()){
System.out.println(list.getFirst());//a
System.out.println(list.getLast());//c
}
}
/*
public E removeFrist(); 移除并返回此列表的第一个元素
public E removeLast(); 移除并返回此列表的最后一个元素
public E pop(E e); 入此列表所示的堆栈中弹出一个元素。
*/
public static void show03(){
LinkedList<String>list = new LinkedList<>();
// add()添加元素
list.add("a");
list.add("b");
list.