目录
1.Collection单列集合
1.1单列集合各集合特点
1.2、Collection集合
1.2.1、Collection方法
1.2.2、Collection遍历方式
1.2.2.1、迭代器遍历集合
1.2.2.2、增强for遍历集合
1.2.2.3、forEach遍历集合(JDK8之后)
1.2.2.4、遍历案例
1.3、List系列集合(List、ArrayList、LinkedList)
1.3.1、List集合的常用方法
1.3.2、List集合的遍历方式
1.3.3、ArrayList集合
1.3.4、LinkedList
1.3.4.1、LinkedList常用方法、
使用LinkedList设计栈结构、队列结构
1.4、Set系列集合(Set、HashSet、LinkedHashSet、TreeSet)
1.4.1、HashSet集合
1.4.1.1、底层原理(了解)
1.4.1.2、HashSet去重原理(重写hashcode、equals方法)
1.4.2、LinkedHashSet集合
1.4.3、TreeSet集合
2、各集合使用情况
3、集合的并发修改异常
3.1解决方法
4、Collection其他使用
4.1、可变参数
4.2、Collections工具类
集合分为单列集合和双列集合:

1.Collection单列集合
1.1单列集合各集合特点
1.2、Collection集合
1.2.1、Collection方法
Collection<String> c = new ArrayList<>();
//1.public boolean add(E e): 添加元素到集合
c.add("java1");
c.add("java1");
c.add("java2");
c.add("java2");
c.add("java3");
System.out.println(c); //打印: [java1, java1, java2, java2, java3]
//2.public int size(): 获取集合的大小
System.out.println(c.size()); //5
//3.public boolean contains(Object obj): 判断集合中是否包含某个元素
System.out.println(c.contains("java1")); //true
System.out.println(c.contains("Java1")); //false
//4.pubilc boolean remove(E e): 删除某个元素,如果有多个重复元素只能删除第一个
System.out.println(c.remove("java1")); //true
System.out.println(c); //打印: [java1,java2, java2, java3]
//5.public void clear(): 清空集合的元素
c.clear();
System.out.println(c); //打印:[]
//6.public boolean isEmpty(): 判断集合是否为空 是空返回true 反之返回false
System.out.println(c.isEmpty()); //true
//7.public Object[] toArray(): 把集合转换为数组
Object[] array = c.toArray();
System.out.println(Arrays.toString(array)); //[java1,java2, java2, java3]
//8.如果想把集合转换为指定类型的数组,可以使用下面的代码
String[] array1 = c.toArray(new String[c.size()]);
System.out.println(Arrays.toString(array1)); //[java1,java2, java2, java3]
//9.还可以把一个集合中的元素,添加到另一个集合中
Collection<String> c1 = new ArrayList<>();
c1.add("java1");
c1.add("java2");
Collection<String> c2 = new ArrayList<>();
c2.add("java3");
c2.add("java4");
c1.addAll(c2); //把c2集合中的全部元素,添加到c1集合中去
System.out.println(c1); //[java1, java2, java3, java4]
1.2.2、Collection遍历方式
1.2.2.1、迭代器遍历集合

代码演示:
Collection<String> c=new ArrayList<>();
c.add("赵敏");
c.add("小昭");
c.add("素素");
c.add("灭绝");
System.out.println(c); //[赵敏, 小昭, 素素, 灭绝]
//第一步:先获取迭代器对象
//解释:Iterator就是迭代器对象,用于遍历集合的工具)
Iterator<String> it=c.iterator();
//第二步:用于判断当前位置是否有元素可以获取
//解释:hasNext()方法返回true,说明有元素可以获取;反之没有
while(it.hasNext()){
//第三步:获取当前位置的元素,然后自动指向下一个元素.
String e=it.next();
System.out.println(s);
}
迭代器代码的原理如下:
当调用iterator()方法获取迭代器时,当前指向第一个元素
hasNext()方法则判断这个位置是否有元素,如果有则返回true,进入循环
调用next()方法获取元素,并将当月元素指向下一个位置,
等下次循环时,则获取下一个元素,依此内推
1.2.2.2、增强for遍历集合

Collection<String> c = new ArrayList<>();
c.add("赵敏");
c.add("小昭");
c.add("素素");
c.add("灭绝");
//1.使用增强for遍历集合
for(String s: c){
System.out.println(s);
}
//2.再尝试使用增强for遍历数组
String[] arr = {"迪丽热巴", "古力娜扎", "稀奇哈哈"};
for(String name: arr){
System.out.println(name);
}
1.2.2.3、forEach遍历集合(JDK8之后)
Collection<String> c = new ArrayList<>();
c.add("赵敏");
c.add("小昭");
c.add("素素");
c.add("灭绝");
//调用forEach方法
//由于参数是一个Consumer接口,所以可以传递匿名内部类
c.forEach(new Consumer<String>{
@Override
public void accept(String s){
System.out.println(s);
}
});
1.2.2.4、遍历案例

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;
}
//...get、set、toString()方法自己补上..
}
public class Test{
public static void main(String[] args){
Collection<Movie> movies = new ArrayList<>();
movies.add(new MOvie("《肖申克的救赎》", 9.7, "罗宾斯"));
movies.add(new MOvie("《霸王别姬》", 9.6, "张国荣、张丰毅"));
movies.add(new MOvie("《阿甘正传》", 9.5, "汤姆汉克斯"));
for(Movie movie : movies){
System.out.println("电影名:" + movie.getName());
System.out.println("评分:" + movie.getScore());
System.out.println("主演:" + movie.getActor());
}
}
}
1.3、List系列集合(List、ArrayList、LinkedList)

1.3.1、List集合的常用方法

接下来,我们用代码演示一下这几个方法的效果
//1.创建一个ArrayList集合对象(有序、有索引、可以重复)
List<String> list = new ArrayList<>();
list.add("蜘蛛精");
list.add("至尊宝");
list.add("至尊宝");
list.add("牛夫人");
System.out.println(list); //[蜘蛛精, 至尊宝, 至尊宝, 牛夫人]
//2.public void add(int index, E element): 在某个索引位置插入元素
list.add(2, "紫霞仙子");
System.out.println(list); //[蜘蛛精, 至尊宝, 紫霞仙子, 至尊宝, 牛夫人]
//3.public E remove(int index): 根据索引删除元素, 返回被删除的元素
System.out.println(list.remove(2)); //紫霞仙子
System.out.println(list);//[蜘蛛精, 至尊宝, 至尊宝, 牛夫人]
//4.public E get(int index): 返回集合中指定位置的元素
System.out.println(list.get(3));
//5.public E set(int index, E e): 修改索引位置处的元素,修改后,会返回原数据
System.out.println(list.set(3,"牛魔王")); //牛夫人
System.out.println(list); //[蜘蛛精, 至尊宝, 至尊宝, 牛魔王]
1.3.2、List集合的遍历方式
- 普通for循环(只因为List有索引)
- 迭代器
- 增强for
- forEach遍历Lambda表达式
List<String> list = new ArrayList<>();
list.add("蜘蛛精");
list.add("至尊宝");
list.add("糖宝宝");
//1.普通for循环
for(int i = 0; i< list.size(); i++){
//i = 0, 1, 2
String e = list.get(i);
System.out.println(e);
}
//2.增强for遍历
for(String s : list){
System.out.println(s);
}
//3.迭代器遍历
Iterator<String> it = list.iterator();
while(it.hasNext()){
String s = it.next();
System.out.println(s);
}
//4.lambda表达式遍历
list.forEach(s->System.out.println(s));
1.3.3、ArrayList集合
1.3.4、LinkedList


1.3.4.1、LinkedList常用方法、

使用LinkedList设计栈结构、队列结构

//1.创建一个队列:先进先出、后进后出
LinkedList<String> queue = new LinkedList<>(); //这是linkedlist独有的所以不能多态
//入对列
queue.addLast("第1号人");
queue.addLast("第2号人");
queue.addLast("第3号人");
queue.addLast("第4号人");
System.out.println(queue);
//出队列
System.out.println(queue.removeFirst()); //第4号人
System.out.println(queue.removeFirst()); //第3号人
System.out.println(queue.removeFirst()); //第2号人
System.out.println(queue.removeFirst()); //第1号人

接着,我们就用LinkedList来模拟下栈结构,代码如下:
//1.创建一个栈对象
LinkedList<String> stack = new LinkedList<>();
//压栈(push) 等价于 addFirst()
stack.push("第1颗子弹");
stack.push("第2颗子弹");
stack.push("第3颗子弹");
stack.push("第4颗子弹");
System.out.println(stack); //[第4颗子弹, 第3颗子弹, 第2颗子弹,第1颗子弹]
//弹栈(pop) 等价于 removeFirst()
System.out.println(statck.pop()); //第4颗子弹
System.out.println(statck.pop()); //第3颗子弹
System.out.println(statck.pop()); //第2颗子弹
System.out.println(statck.pop()); //第1颗子弹
//弹栈完了,集合中就没有元素了
System.out.println(list); //[]
1.4、Set系列集合(Set、HashSet、LinkedHashSet、TreeSet)


1.4.1、HashSet集合
1.4.1.1、底层原理(了解)


- 只有新添加元素的hashCode值和集合中以后元素的hashCode值相同、新添加的元素调用equals方法和集合中已有元素比较结果为true, 才认为元素重复。
- 如果hashCode值相同,equals比较不同,则以链表的形式连接在数组的同一个索引为位置(如上图所示)
1.4.1.2、HashSet去重原理(重写hashcode、equals方法)
public class Student{
private String name; //姓名
private int age; //年龄
private double height; //身高
//无参数构造方法
public Student(){}
//全参数构造方法
public Student(String name, int age, double height){
this.name=name;
this.age=age;
this.height=height;
}
//...get、set、toString()方法自己补上..
//按快捷键生成hashCode和equals方法
//alt+insert 选择 hashCode and equals
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Student student = (Student) o;
if (age != student.age) return false;
if (Double.compare(student.height, height) != 0) return false;
return name != null ? name.equals(student.name) : student.name == null;
}
@Override
public int hashCode() {
int result;
long temp;
result = name != null ? name.hashCode() : 0;
result = 31 * result + age;
temp = Double.doubleToLongBits(height);
result = 31 * result + (int) (temp ^ (temp >>> 32));
return result;
}
}
public class Test{
public static void main(String[] args){
Set<Student> students = new HashSet<>();
Student s1 = new Student("至尊宝",20, 169.6);
Student s2 = new Student("蜘蛛精",23, 169.6);
Student s3 = new Student("蜘蛛精",23, 169.6);
Student s4 = new Student("牛魔王",48, 169.6);
students.add(s1);
students.add(s2);
students.add(s3);
students.add(s4);
for(Student s : students){
System.out.println(s);
}
}
}

1.4.2、LinkedHashSet集合

public class Test{
public static void main(String[] args){
Set<Student> students = new LinkedHashSet<>();
Student s1 = new Student("至尊宝",20, 169.6);
Student s2 = new Student("蜘蛛精",23, 169.6);
Student s3 = new Student("蜘蛛精",23, 169.6);
Student s4 = new Student("牛魔王",48, 169.6);
students.add(s1);
students.add(s2);
students.add(s3);
students.add(s4);
for(Student s : students){
System.out.println(s);
}
}
}
1.4.3、TreeSet集合
Set<Integer> set1= new TreeSet<>();
set1.add(8);
set1.add(6);
set1.add(4);
set1.add(3);
set1.add(7);
set1.add(1);
set1.add(5);
set1.add(2);
System.out.println(set1); //[1,2,3,4,5,6,7,8]
Set<Integer> set2= new TreeSet<>();
set2.add("a");
set2.add("c");
set2.add("e");
set2.add("b");
set2.add("d");
set2.add("f");
set2.add("g");
System.out.println(set1); //[a,b,c,d,e,f,g]
2.如果往TreeSet集合中存储自定义类型的元素,比如说Student类型,则需要自己指定排序规则,否则会出现异常。
错误情况:
//创建TreeSet集合,元素为Student类型
Set<Student> students = new TreeSet<>();
//创建4个Student对象
Student s1 = new Student("至尊宝",20, 169.6);
Student s2 = new Student("紫霞",23, 169.8);
Student s3 = new Student("蜘蛛精",23, 169.6);
Student s4 = new Student("牛魔王",48, 169.6);
//添加Studnet对象到集合
students.add(s1);
students.add(s2);
students.add(s3);
students.add(s4);
System.out.println(students);
- 第一种:让元素的类实现Comparable接口,重写compareTo方法
- 第二种:在创建TreeSet集合时,通过构造方法传递Compartor比较器对象
//第一步:先让Student类,实现Comparable接口
//注意:Student类的对象是作为TreeSet集合的元素的
public class Student implements Comparable<Student>{
private String name;
private int age;
private double height;
//无参数构造方法
public Student(){}
//全参数构造方法
public Student(String name, int age, double height){
this.name=name;
this.age=age;
this.height=height;
}
//...get、set、toString()方法自己补上..
//第二步:重写compareTo方法
//按照年龄进行比较,只需要在方法中让this.age和o.age相减就可以。
/*
原理:
在往TreeSet集合中添加元素时,add方法底层会调用compareTo方法,根据该方法的
结果是正数、负数、还是零,决定元素放在后面、前面还是不存。
*/
@Override
public int compareTo(Student o) {
//this:表示将要添加进去的Student对象
//o: 表示集合中已有的Student对象
return this.age-o.age;
}
}
此时,再运行测试类,结果如下
Student{name='至尊宝', age=20, height=169.6}
Student{name='紫霞', age=20, height=169.8}
Student{name='蜘蛛精', age=23, height=169.6}
Student{name='牛魔王', age=48, height=169.6}
//创建TreeSet集合时,传递比较器对象排序
/*
原理:当调用add方法时,底层会先用比较器,根据Comparator的compare方是正数、负数、还是零,决定谁在后,谁在前,谁不存。
*/
//下面代码中是按照学生的年龄升序排序
Set<Student> students = new TreeSet<>(new Comparator<Student>{
@Override
public int compare(Student o1, Student o2){
//需求:按照学生的身高排序
return Double.compare(o1,o2);
}
});
//创建4个Student对象
Student s1 = new Student("至尊宝",20, 169.6);
Student s2 = new Student("紫霞",23, 169.8);
Student s3 = new Student("蜘蛛精",23, 169.6);
Student s4 = new Student("牛魔王",48, 169.6);
//添加Studnet对象到集合
students.add(s1);
students.add(s2);
students.add(s3);
students.add(s4);
System.out.println(students);
2、各集合使用情况

3、集合的并发修改异常
其实就是删除一个元素后,集合位置会发生改变,但是索引接着往下走产生的原因,导致有些数据没办法被索引指到的问题
List<String> list = new ArrayList<>();
list.add("王麻子");
list.add("小李子");
list.add("李爱花");
list.add("张全蛋");
list.add("晓李");
list.add("李玉刚");
System.out.println(list); // [王麻子, 小李子, 李爱花, 张全蛋, 晓李, 李玉刚]
//需求:找出集合中带"李"字的姓名,并从集合中删除
Iterator<String> it = list.iterator();
while(it.hasNext()){
String name = it.next();
if(name.contains("李")){
list.remove(name);
}
}
System.out.println(list);
使用for方法看,要加入i--才会执行成功

3.1解决方法
List<String> list = new ArrayList<>();
list.add("王麻子");
list.add("小李子");
list.add("李爱花");
list.add("张全蛋");
list.add("晓李");
list.add("李玉刚");
System.out.println(list); // [王麻子, 小李子, 李爱花, 张全蛋, 晓李, 李玉刚]
//需求:找出集合中带"李"字的姓名,并从集合中删除
Iterator<String> it = list.iterator();
while(it.hasNext()){
String name = it.next();
if(name.contains("李")){
//list.remove(name);
it.remove(); //当前迭代器指向谁,就删除谁
}
}
System.out.println(list);

4、Collection其他使用
4.1、可变参数

public class ParamTest{
public static void main(String[] args){
//不传递参数,下面的nums长度则为0, 打印元素是[]
test();
//传递3个参数,下面的nums长度为3,打印元素是[10, 20, 30]
test(10,20,30);
//传递一个数组,下面数组长度为4,打印元素是[10,20,30,40]
int[] arr = new int[]{10,20,30,40}
test(arr);
}
public static void test(int...nums){
//可变参数在方法内部,本质上是一个数组
System.out.println(nums.length);
System.out.println(Arrays.toString(nums));
System.out.println("----------------");
}
}
4.2、Collections工具类
public class CollectionsTest{
public static void main(String[] args){
//1.public static <T> boolean addAll(Collection<? super T> c, T...e)对集合批量添加数据
List<String> names = new ArrayList<>();
Collections.addAll(names, "张三","王五","李四", "张麻子");
System.out.println(names);
//2.public static void shuffle(List<?> list):对List集合打乱顺序
Collections.shuffle(names);
System.out.println(names);
//3.public static <T> void short(List<T list): 对List集合排序
List<Integer> list = new ArrayList<>();
list.add(3);
list.add(5);
list.add(2);
Collections.sort(list);
System.out.println(list);
}
}
public class Student implements Comparable<Student>{
private String name;
private int age;
private double height;
//排序时:底层会自动调用此方法,this和o表示需要比较的两个对象
@Override
public int compareTo(Student o){
//需求:按照年龄升序排序
//如果返回正数:说明左边对象的年龄>右边对象的年龄
//如果返回负数:说明左边对象的年龄<右边对象的年龄,
//如果返回0:说明左边对象的年龄和右边对象的年龄相同
return this.age - o.age;
}
//...getter、setter、constructor..
}
//3.public static <T> void short(List<T list): 对List集合排序
List<Student> students = new ArrayList<>();
students.add(new Student("蜘蛛精",23,169.7));
students.add(new Student("紫霞",22,169.8));
students.add(new Student("紫霞",22,169.8));
students.add(new Student("至尊宝",26,169.5));
/*
原理:sort方法底层会遍历students集合中的每一个元素,采用排序算法,将任意两个元素两两比较;
每次比较时,会用一个Student对象调用compareTo方法和另一个Student对象进行比较;
根据compareTo方法返回的结果是正数、负数,零来决定谁大,谁小,谁相等,重新排序元素的位置
注意:这些都是sort方法底层自动完成的,想要完全理解,必须要懂排序算法才行;
*/
Collections.sort(students);
System.out.println(students);
/*
原理:sort方法底层会遍历students集合中的每一个元素,采用排序算法,将任意两个元素两两比较;
每次比较,会将比较的两个元素传递给Comparator比较器对象的compare方法的两个参数o1和o2,
根据compare方法的返回结果是正数,负数,或者0来决定谁大,谁小,谁相等,重新排序元素的位置
注意:这些都是sort方法底层自动完成的,不需要我们完全理解,想要理解它必须要懂排序算法才行.
*/
Collections.sort(students, new Comparator<Student>(){
@Override
public int compare(Student o1, Student o2){
return o1.getAge()-o2.getAge();
}
});
System.out.println(students);



















