集合
1、集合的概述
集合和数组都是容器
-
数组定义完成并启动后,类型确定、长度固定。
-
数组可以存储基本类型和引用类型的数据。
-
适合元素的个数和类型确定的业务场景,不适合做需要增删数据操作。
-
集合的大小不固定,启动后可以动态变化,类型也可以选择不固定。
-
集合只能存储引用数据类型的数据。
-
集合非常适合做元素的增删操作。
2、集合的体系

List系列集合:添加的元素是有序、可重复、有索引。
- ArrayList、LinekdList :有序、可重复、有索引。
Set系列集合:添加的元素是无序、不重复、无索引。
- HashSet:无序、不重复、无索引;
- LinkedHashSet:有序、不重复、无索引。
- TreeSet:按照大小默认升序排序、不重复、无索引。
集合都是支持泛型的,可以在编译阶段约束集合只能操作某种数据类型。
3、Collection的常用方法
Collection是单列集合的祖宗接口,它的功能是全部单列集合都可以继承使用的。
| 方法名 | 称说明 |
|---|---|
| public boolean add(E e) | 把给定的对象添加到当前集合中 |
| public void clear() | 清空集合中所有的元素 |
| public boolean remove(E e) | 把给定的对象在当前集合中删除 |
| public boolean contains(Object obj) | 判断当前集合中是否包含给定的对象 |
| public boolean isEmpty() | 判断当前集合是否为空 |
| public int size() | 返回集合中元素的个数 |
| public Object[] toArray() | 把集合中的元素,存储到数组中 |
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
public class CollectionDemo {
public static void main(String[] args) {
// HashSet:添加的元素是无序,不重复,无索引。
Collection<String> c = new ArrayList<>();
// 1.添加元素, 添加成功返回true。
c.add("Java");
c.add("HTML");
System.out.println(c.add("HTML"));
c.add("MySQL");
c.add("Java");
System.out.println(c.add("后端"));
System.out.println(c); // [Java, HTML, HTML, MySQL, Java, 后端]
// 2.清空集合的元素。
// c.clear();
// System.out.println(c);
// 3.判断集合是否为空 是空返回true,反之。
// System.out.println(c.isEmpty());
// 4.获取集合的大小。
System.out.println(c.size());
// 5.判断集合中是否包含某个元素。
System.out.println(c.contains("Java")); // true
System.out.println(c.contains("java")); // false
System.out.println(c.contains("后端")); // true
// 6.删除某个元素:如果有多个重复元素默认删除前面的第一个!
System.out.println(c.remove("java")); // false
System.out.println(c);
System.out.println(c.remove("Java")); // true
System.out.println(c);
// 7.把集合转换成数组 [HTML, HTML, MySQL, Java, 后端]
Object[] arrs = c.toArray();
System.out.println("数组:" + Arrays.toString(arrs));
System.out.println("----------------------拓展----------------------");
Collection<String> c1 = new ArrayList<>();
c1.add("java1");
c1.add("java2");
Collection<String> c2 = new ArrayList<>();
c2.add("赵敏");
c2.add("殷素素");
// addAll把c2集合的元素全部倒入到c1中去。
c1.addAll(c2);
System.out.println(c1);
System.out.println(c2);
}
}
4、集合的遍历方式
4.1 方式一:迭代器
遍历就是一个一个的把容器中的元素访问一遍。
迭代器在Java中的代表是lterator,迭代器是集合的专用遍历方式。
Collection集合获取迭代器
| 方法名称 | 说明 |
|---|---|
| Iterator iterator() | 返回集合中的迭代器对象,该迭代器对象默认指向当前集合的O索引 |
lterator中的常用方法
| 方法名称 | 说明 |
|---|---|
| boolean hasNext() | 询问当前位置是否有元素存在,存在返回true ,不存在返回false |
| E next() | 获取当前位置的元素,并同时将迭代器对象移向下一个位置,注意防止取出越界 |
import java.util.ArrayList;
import java.util.Iterator;
public class Test {
public static void main(String[] args) {
ArrayList<String> lists = new ArrayList<>();
lists.add("赵敏");
lists.add("小昭");
lists.add("素素");
lists.add("灭绝");
System.out.println(lists);
// [赵敏, 小昭, 素素, 灭绝]
// 1、得到当前集合的迭代器对象。
Iterator<String> it = lists.iterator();
// 2、定义while循环
while (it.hasNext()){
String ele = it.next();
System.out.println(ele);
}
System.out.println("-----------------------------");
}
}

4.2 方式二:foreach/增强for循环
增强for循环,既可以遍历集合也可以遍历数组。
for(元素数据类型 变量名:数组或者Collection集合){
//在此处使用变量即可,该变量就是元素
}

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
public class Test {
public static void main(String[] args) {
Collection<String> lists = new ArrayList<>();
lists.add("赵敏");
lists.add("小昭");
lists.add("殷素素");
lists.add("周芷若");
System.out.println(lists);
// [赵敏, 小昭, 殷素素, 周芷若]
// ele
for (String ele : lists) {
System.out.println(ele);
}
System.out.println("------------------");
double[] scores = {100, 99.5 , 59.5};
for (double score : scores) {
System.out.println(score);
// if(score == 59.5){
// score = 100.0; // 修改无意义,不会影响数组的元素值。
// }
}
System.out.println(Arrays.toString(scores));
}
}
4.3 方式三:lambda表达式
得益于JDK 8开始的新技术Lambda表达式,提供了一种更简单、更直接的遍历集合的方式。
Collection结合Lambda遍历的APl
| 方法名称 | 说明 |
|---|---|
| default void forEach(consumer< ?super T> action): | 结合lambda遍历集合 |
![]() |
import java.util.ArrayList;
import java.util.Collection;
import java.util.function.Consumer;
public class Test {
public static void main(String[] args) {
Collection<String> lists = new ArrayList<>();
lists.add("赵敏");
lists.add("小昭");
lists.add("殷素素");
lists.add("周芷若");
System.out.println(lists);
// [赵敏, 小昭, 殷素素, 周芷若]
// s
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) );
lists.forEach(System.out::println );
}
}
5、 集合存储自定义类型的对象
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 + '\'' +
'}';
}
}
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());
}
}
}

集合中存储的是元素对象的地址。
6、常见的数据结构
参见数据结构系列博客 数据结构笔记。
7、List系列集合
7.1 List集合特点
ArrayList、 LinekdList :有序,可重复,有索引。
- 有序:存储和取出的元素顺序一致
- 有索引:可以通过索引操作元素
- 可重复: 存储的元素可以重复
ArrayList底层是基于数组实现的,根据查询元素快,增删相对慢。
LinkedList底层基于双链表实现的,查询元素慢,增删首尾元素是非常快的。
List集合特有方法
List集合因为支持索引, 所以多了很多索弓|操作的独特api,其他Collection的功能List也都继承了。
| 方法名称 | 说明 |
|---|---|
| void add(int index,E element) | 在此集合中的指定位置插入指定的元素 |
| E remove(int index) | 删除指定索引处的元素,返回被删除的元素 |
| E set(int index,E element) | 修改指定索引处的元素,返回被修改的元素 |
| E get(int index) | 返回指定索引 |
import java.util.ArrayList;
public class Test {
public static void main(String[] args) {
// 1.创建一个ArrayList集合对象:
// List:有序,可重复,有索引的。
ArrayList<String> list = new ArrayList<>(); // 一行经典代码!
list.add("Java");
list.add("Java");
list.add("HTML");
list.add("HTML");
list.add("MySQL");
list.add("MySQL");
// 2.在某个索引位置插入元素。
list.add(2, "后端");
System.out.println(list);
// 3.根据索引删除元素,返回被删除元素
System.out.println(list.remove(1));
System.out.println(list);
// 4.根据索引获取元素:public E get(int index):返回集合中指定位置的元素。
System.out.println(list.get(1));
// 5.修改索引位置处的元素: public E set(int index, E element)
System.out.println(list.set(1, "前端"));
System.out.println(list);
}
}
7.2 List集合遍历
- 迭代器
- 增强for循环
- Lambda表达式
- for循环(因为List集合存在索引)
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
public class Test{
public static void main(String[] args) {
List<String> lists = new ArrayList<>();
lists.add("java1");
lists.add("java2");
lists.add("java3");
/* (1)for循环。 */
System.out.println("-----------------------");
for (int i = 0; i < lists.size(); i++) {
String ele = lists.get(i);
System.out.println(ele);
}
/* (2)迭代器。 */
System.out.println("-----------------------");
Iterator<String> it = lists.iterator();
while (it.hasNext()){
String ele = it.next();
System.out.println(ele);
}
/* (3)foreach */
System.out.println("-----------------------");
for (String ele : lists) {
System.out.println(ele);
}
/* (4)JDK 1.8开始之后的Lambda表达式 */
System.out.println("-----------------------");
lists.forEach(s -> {
System.out.println(s);
});
}
}
7.3 ArrayList集合的底层原理
- Araylist底层是基于数组实现的:根据索引定位元素快,增删需要做元素的移位操作。
- 第一次创建集合并添加第一个元素的时候, 在底层创建一个默认长度为10的数组。

7.4 LinkedList集合的底层原理
底层数据结构是双链表,查询慢,首尾操作的速度是极快的,所以多了很多首尾操作的特有API。
LinkedList集合的特有功能
| 方法名称 | 说明 |
|---|---|
| public void adFirst(E e) | 在该列表开头插入指定的元素 |
| public void addLast(E e) | 将指定的元素追加到此列表的末尾 |
| public E getFirst() | 返回此列表中的第一个元素 |
| public E getLast() | 返回此列表中的最后一个元素 |
| public E removeFirst() | 从此列表中删除并返回第一个元素 |
| public E removeLast() | 从此列表中删除并返回最后一个元素 |
![]() |
8、集合的并发修改异常问题
当我们从集合中找出某个元素并删除的时候可能出现一 种并发修改异常问题。
哪些遍历存在问题?
- 迭代器遍历集合且直接用集合删除元素的时候可能出现。
- 增强for循环遍历集合且直接用集合删除元素的时候可能出现。
哪种遍历且删除元素不出问题
- 迭代器遍历集合但是用迭代器自己的删除方法操作可以解决。
- 使用for循环遍历并删除元素不会存在这个问题。
9、泛型深入
9.1 泛型的概述和优势
泛型概述
- 泛型:是JDK5中引入的特性,可以在编译阶段约束操作的数据类型,并进行检查。
- 泛型的格式: <数据类型>; 注意:泛型只能支持引|用数据类型。
- 集合体系的全部接口和实现类都是支持泛型的使用的。
泛型的好处:
- 统一数据类型。
- 把运行时期的问题提前到了编译期间,避免了强制类型转换可能出现的异常,因为编译阶段类型就能确定下来。

9.2 自定义泛型类
泛型类的概述
- 定义类时同时定义了泛型的类就是泛型类。
- 泛型类的格式:修饰符class类名<泛型变量>{ }
范例: public class MyArrayList<T> { }
此处泛型变量T可以随便写为任意标识, 常见的如E、T、K、V等。
作用:编译阶段可以指定数据类型,类似于集合的作用。
模拟ArrayList集合自定义一 个集合MyArrayList集合,完成添加和删除功能的泛型设计即可。
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();
}
}
public class Test {
public static void main(String[] args) {
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);
}
}
泛型类的原理:
把出现泛型变量的地方全部替换成传输的真实数据类型。
9.3 自定义泛型方法
泛型方法的概述
- 定义方法时同时定义了泛型的方法就是泛型方法。
- 泛型方法的格式:修饰符<泛型变量>方法返回值方法名称(形参列表){}
范例: public <T> void show(T t){ }
作用:方法中可以使用泛型接收一切实际类型的参数,方法更具备通用性。
public class Test {
public static void main(String[] args) {
String[] names = {"小璐", "蓉容", "小何"};
printArray(names);
Integer[] ages = {10, 20, 30};
printArray(ages);
Integer[] ages2 = getArr(ages);
String[] names2 = getArr(names);
}
public static <T> T[] getArr(T[] arr){
return arr;
}
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);
}
}
}
给你任何一个类型的数组,都能返回它的内容。也就是实现Arrays.toString(数组)的功能!
泛型方法的原理:
把出现泛型变量的地方全部替换成传输的真实数据类型。
9.4 自定义泛型接口
泛型接口的概述
- 使用了泛型定义的接口就是泛型接口。
- 泛型接口的格式:修饰符interface 接口名称<泛型变量>{}
范例: public interface Data<E>{}
作用:泛型接口可以让实现类选择当前功能需要操作的数据类型
泛型接口的原理:
实现类可以在实现接口的时候传入自己操作的数据类型,这样重写的方法都将是针对于该类型的操作。
9.5 泛型通配符、上下限
通配符:?
- ?可以在“使用泛型”的时候代表一切类型。
- ET KV是在定义泛型的时候使用的。
开发一个极品飞车的游戏,所有的汽车都能一 起参与比赛。
import java.util.ArrayList;
public class GenericDemo {
public static void main(String[] args) {
ArrayList<BMW> bmws = new ArrayList<>();
bmws.add(new BMW());
bmws.add(new BMW());
bmws.add(new BMW());
go(bmws);
ArrayList<BENZ> benzs = new ArrayList<>();
benzs.add(new BENZ());
benzs.add(new BENZ());
benzs.add(new BENZ());
go(benzs);
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{
}
注意:
●虽然BMW和BENZ都继承了Car但是ArrayList < BMW>和ArrayList与ArrayList没有关系的! !
泛型的上下限: .
- ? extends Car: ?必须是Car或者其子类泛型上限
- ? super Car : ?必须是Car或者其父类 泛型下限


1032

被折叠的 条评论
为什么被折叠?



