一.单列集合体系结构
- List系列集合:添加的元素时有序,可重复,有索引
- Set系列集合:添加的元素时无序,不重复,无索引
二.单列集合的通用方法

1.1基本数据类型的用法
java
package 集合;
import java.util.ArrayList;
import java.util.Collection;
public class demo1 {
public static void main(String[] args) {
// 1. 使用多态方式创建集合
Collection<String> list = new ArrayList<>();
// 输出空列表:[]
System.out.println(list);
// 2.添加元素,添加成功返回true
boolean result1 = list.add("1");
boolean result2 = list.add("2");
boolean result3 = list.add("3");
System.out.println(result1); // true
System.out.println(list);
// 3.删除元素,删除成功返回true
list.remove("2");
System.out.println(list);
// 4. 集合长度
System.out.println(list.size()); // 2
// 5. 集合是否为空
System.out.println(list.isEmpty()); // false
// 6. 集合是否包含某个元素
System.out.println(list.contains("1")); // true
}
}
1.2引用数据类型的用法
java
public static void main(String[] args) {
ArrayList<Student> list = new ArrayList<Student>();
Student s1 = new Student("张三", 12);
Student s2 = new Student("李四", 13);
Student s3 = new Student("王五", 14);
list.add(s1);
list.add(s2);
list.add(s3);
for (int i = 0; i < list.size(); i++) {
System.out.println(list.get(i).getName() + "," + list.get(i).getAge());
}
for (int i = 0; i < 3; i++) {
Student s = new Student();
Scanner sc = new Scanner(System.in);
System.out.println("输入学生姓名:");
String name = sc.nextLine();
System.out.println("输入学生年龄");
int age = sc.nextInt();
s.setName(name);
s.setAge(age);
list.add(s);
}
for (int i = 0; i < list.size(); i++) {
System.out.println(list.get(i).getName() + "," + list.get(i).getAge());
}
}
2.遍历集合
1.迭代器
先获取数据,再移动指针,遍历后指针不复位,既依然指向最后没有数据的位置,删除时只能使用迭代器的remove方法,不能使用集合的remove方法
java
package 集合;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.function.Consumer;
public class demo1 {
public static void main(String[] args) {
Collection<String> list = new ArrayList<>();
list.add("a");
list.add("b");
list.add("c");
Iterator<String> it1 = list.iterator();
while(it1.hasNext()){
String s = it1.next();
System.out.println(s);
}
Iterator<String> it2 = list.iterator();
while(it2.hasNext()){
String s = it2.next();
if("b".equals(s)){
it2.remove();
}
}
System.out.println(list);
}
}
java
a
b
c
[a, c]
2.增强for
增强for: 内部原理是迭代器,只能遍历单列集合,数组,不能遍历Set双列集合
java
package 集合;
import java.util.ArrayList;
import java.util.Collection;
public class demo1 {
public static void main(String[] args) {
Collection<String> list = new ArrayList<>();
list.add("a");
list.add("b");
list.add("c");
for (String s : list) {
//s = "d";//不能修改集合中的元素
System.out.println(s);
}
}
}
java
a
b
c
3.使用forEach+lambda
java
package 集合;
import java.util.ArrayList;
import java.util.Collection;
import java.util.function.Consumer;
public class demo1 {
public static void main(String[] args) {
Collection<String> list = new ArrayList<>();
list.add("a");
list.add("b");
list.add("c");
list.forEach(new Consumer<String>() {
@Override
public void accept(String s) {
System.out.println(s);
}
});
list.forEach((String s) -> System.out.println(s));
//等同于:list.forEach(s -> System.out.println(s));
}
}
java
a
b
c
a
b
c
三.集合list的特有方法
特性 | ArrayList | LinkedList |
---|---|---|
底层数据结构 | 动态数组 | 双向链表 |
访问元素 | 极快,通过索引直接访问,时间复杂度 O(1) | 慢,需要从头或尾遍历,时间复杂度 O(n) |
插入/删除元素 | 慢,需要移动后续元素,时间复杂度 O(n) | 快,只需修改指针,时间复杂度 O(1) |
内存开销 | 较小,只存储数据和数组容量 | 较大,每个节点都需要存储数据和两个指针 |
适用场景 | 频繁随机访问,多读少写 | 频繁在头尾或中间插入/删除,少随机访问 |
ArrayList
和 LinkedList
都实现了 List<E>
接口。这意味着它们对外承诺了完全相同的一组方法。因此,从代码编写的角度来看,你可以用完全相同的方式去调用 add(int index, E element)
, remove(int index)
, set(int index, E element)
, get(int index)
这些方法,而不需要关心底层是数组还是链表.
有序可重复
- 有序: 元素有索引,可以根据索引操作元素
- 可重复: 集合中可以存储重复元素

1.void add(int index ,E element)
java
package 集合;
import java.util.ArrayList;
import java.util.List;
public class demo1 {
public static void main(String[] args) {
List<Integer> list = new ArrayList<>();
list.add(3);
list.add(2);
list.add(1);
System.out.println(list);
list.add(1,5);
System.out.println(list);
}
}
java
[3, 2, 1]
[3, 5, 2, 1]
2.remove(int index)/remove(Object O)
- remove(int index): 删除指定索引处的元素,返回被删除的元素
- remove(Object o): 删除指定元素,返回是否删除成功
java
package 集合;
import java.util.ArrayList;
import java.util.List;
public class demo1 {
public static void main(String[] args) {
List<Integer> list = new ArrayList<>();
list.add(3);
list.add(2);
list.add(1);
System.out.println(list);
list.remove(Integer.valueOf(2));
System.out.println(list);
list.remove(1);
System.out.println(list);
}
}
java
[3, 2, 1]
[3, 1]
[3]
因为在调用方法时,如果出现了重载的现象,优先调用实参跟形参类型一致的方法(缺少了封箱这一步)
3.set(int index,E element)
java
package 集合;
import java.util.ArrayList;
import java.util.List;
public class demo1 {
public static void main(String[] args) {
List<Integer> list = new ArrayList<>();
list.add(3);
list.add(2);
list.add(1);
System.out.println(list);
list.set(0, 100);
System.out.println(list);
}
}
java
[3, 2, 1]
[100, 2, 1]
4.get(int index)
java
package 集合;
import java.util.ArrayList;
import java.util.List;
public class demo1 {
public static void main(String[] args) {
List<Integer> list = new ArrayList<>();
list.add(3);
list.add(2);
list.add(1);
System.out.println(list.get(1));
}
}
java
2
5.列表遍历
1.普通for循环与增强for循环
因为list是有序的,所以可以使用索引
java
package 集合;
import java.util.ArrayList;
import java.util.List;
public class demo1 {
public static void main(String[] args) {
List<Integer> list = new ArrayList<>();
list.add(3);
list.add(2);
list.add(1);
for (Integer i : list) {
System.out.println(i);
}
System.out.println("-----------------");
for(int i = 0;i<list.size();i++){
System.out.println(list.get(i));
}
}
}
java
3
2
1
-----------------
3
2
1
2.列表迭代器
java
package 集合;
import java.util.ArrayList;
import java.util.List;
import java.util.ListIterator;
public class demo1 {
public static void main(String[] args) {
List<Integer> list = new ArrayList<>();
list.add(3);
list.add(2);
list.add(1);
ListIterator<Integer> listit = list.listIterator();
while(listit.hasNext()){
Integer i = listit.next();
if(i == 2){
listit.add(521);
}
System.out.println(i);
}
System.out.println(list);
}
}
java
3
2
1
[3, 2, 521, 1]
对比总结
特性维度 | 迭代器遍历 | 增强for循环 | 普通for循环 | 列表迭代器 | forEach遍历 |
---|---|---|---|---|---|
删除能力 | ✅ 安全删除 | ❌ 不支持 | ⚠️ 需手动调整索引 | ✅ 安全删除 | ❌ 不支持 |
添加能力 | ❌ 不支持 | ❌ 不支持 | ⚠️ 需手动调整索引 | ✅ 支持添加 | ❌ 不支持 |
修改能力 | ❌ 不支持 | ❌ 不支持 | ✅ 直接修改 | ✅ 支持修改 | ❌ 不支持 |
双向遍历 | ❌ 单向 | ❌ 单向 | ⚠️ 可反向但复杂 | ✅ 双向 | ❌ 单向 |
适用集合 | 所有Collection | 数组+Iterable | 仅List | 仅List | 所有Iterable |
- 迭代器循环:在遍历过程中需要删除元素
- 增强for循环:仅仅遍历
- forEach:仅仅遍历
- 普通for循环:需要对索引进行操作
- 使用列表迭代器:在遍历过程中需要添加元素
四.底层原理
1.ArrayList
- 利用空参构造创建的集合,在底层创建一个默认长度为0的数组
- 在添加第一个元素时,底层会创建一个新的长度为10的数组
- 存满时,会扩容1.5倍
- 如果一次性添加多个元素,1.5倍放不下,则新创建的数组长度以实际为准
2.LinkedList

3.iterator

五.集合Set
特性 | HashSet | TreeSet |
---|---|---|
底层数据结构 | 基于 HashMap (哈希表) | 基于 TreeMap (红黑树) |
元素顺序 | 无序(不保证插入顺序或任何特定顺序) | 有序(按元素的自然顺序或自定义比较器排序) |
性能 (增、删、查) | O(1) 平均时间复杂度 | O(log n) 平均时间复杂度 |
元素要求 | 必须正确实现 equals() 和 hashCode() 方法 |
必须实现 Comparable 接口 或 提供 Comparator |
允许 null 元素 | 允许 一个 null 元素 |
不允许 (如果使用自然排序,因为 null 无法比较) |
线程安全 | 非线程安全 | 非线程安全 |
1.HashSet
赖 hashCode
和 equals
:
-
当添加元素时,
HashSet
会调用元素的hashCode()
方法来确定存储位置。 -
如果两个元素的
hashCode
相同,它会再调用equals()
方法来检查它们是否真的相等。 -
如果两个对象通过
equals()
比较是相等的,那么它们的hashCode()
必须返回相同的值。 否则,会导致重复元素被加入,破坏了 Set 的唯一性。
在使用引用数据类型时,需要重写hashCode()和equals()方法
String 与 integer 类型都重写了hashCode()和equals()方法
java
import java.util.Objects;
public class Student {
private String name;
private int age;
public Student() {
}
public Student(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Student student = (Student) o;
return age == student.age && Objects.equals(name, student.name);
}
@Override
public int hashCode() {
return Objects.hash(name, age);
}
public String toString() {
return "Student{name = " + name + ", age = " + age + "}";
}
}
java
import java.util.HashSet;
import java.util.Set;
import java.util.TreeSet;
public class test {
public static void main(String[] args) {
Student s1 = new Student("张三", 18);
Student s2 = new Student("张三", 18);
Student s3 = new Student("李四", 19);
Student s4 = new Student("王五", 20);
Set<Student> set = new HashSet<Student>();
set.add(s1);
set.add(s2);
set.add(s3);
set.add(s4);
System.out.println(set);
}
}
java
[Student{name = 张三, age = 18}, Student{name = 王五, age = 20}, Student{name = 李四, age = 19}]
2.TreeSet
TreeSet
是基于红黑树(一种自平衡的二叉搜索树)实现的 Set,它保证了元素处于排序状态。
元素必须可比较:
-
自然排序 :元素类必须实现
java.lang.Comparable
接口,并重写compareTo
方法。 -
定制排序 :在创建
TreeSet
时,传入一个Comparator
比较器对象。
1.实现Comparable接口,并重写 compareTo方法
java
package 集合;
import java.util.Objects;
public class Student implements Comparable<Student> {
private String name;
private int age;
public Student() {
}
public Student(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String toString() {
return "Student{name = " + name + ", age = " + age + "}";
}
@Override
public int compareTo(Student o) {
// this 表示当前要填加的元素, o 表示在红黑树存在的元素
return this.age - o.age;
}
}
java
package 集合;
import java.util.HashSet;
import java.util.Set;
import java.util.TreeSet;
public class test {
public static void main(String[] args) {
Student s1 = new Student("张三", 18);
Student s2 = new Student("张三", 18);
Student s3 = new Student("李四", 19);
Student s4 = new Student("王五", 20);
Set<Student> set2 = new TreeSet<Student>();
set2.add(s1);
set2.add(s2);
set2.add(s3);
set2.add(s4);
System.out.println(set2);
}
}
java
[Student{name = 张三, age = 18}, Student{name = 李四, age = 19}, Student{name = 王五, age = 20}]
2.使用比较器
java
import java.util.Comparator;
import java.util.Set;
import java.util.TreeSet;
public class test2 {
public static void main(String[] args) {
// 使用比较器进行排序规则的指定
// 规则当长度相同时,按照字典序排序,长度不同时,按照长度排序
Set<String> set = new TreeSet<>(new Comparator<String>() {
@Override
public int compare(String o1, String o2) {
// o1 表示当前要填加的元素, o2 表示在红黑树存在的元素
int i = o1.length() - o2.length();
i = i==0? o1.compareTo(o2) : i;
return i;
}
});
set.add("a");
set.add("bw");
set.add("qwer");
set.add("s");
System.out.println(set);
}
}
java
[a, s, bw, qwer]
六.泛型
1.泛型类
在集合中不限制子类类型时,会默认为Object类型,可以往集合中添加任意类型的数据,类似于多态形式,但是不可以调用子类的特性
java
// 定义一个泛型类 Box
public class Box<T> {
private T content; // T 代表一个未知的类型
public void setContent(T content) {
this.content = content;
}
public T getContent() {
return content; // 返回类型是 T,不需要强制转换
}
}
在创建类时,使用形参E进行表示,在创建实例对象时,才给出数据类型
java
import java.util.Arrays;
//1.泛型类
public class myArrayList<E>{
Object[] obj = new Object[10];
int size = 0;
// 添加元素
public boolean add(E e){
obj[size] = e;
size++;
return true;
}
public E get(int index){
return (E)obj[index];
}
// 重写toString方法
@Override
public String toString(){
return Arrays.toString(obj);
}
}
java
import java.util.ArrayList;
public class demo1 {
public static void main(String[] args) {
// 1.泛型类
myArrayList<String> list = new myArrayList<>();
list.add("hello");
list.add("world");
System.out.println(list);
java
[hello, world, null, null, null, null, null, null, null, null]
2.泛型方法
java
public class Utility {
// 一个普通的泛型方法(在非泛型类中)
public static <T> void printArray(T[] array) {
for (T element : array) {
System.out.print(element + " ");
}
System.out.println();
}
// 另一个泛型方法,有两个类型参数
public static <T, U> void printPair(T first, U second) {
System.out.println("First: " + first + ", Second: " + second);
}
}
java
public class Main {
public static void main(String[] args) {
Integer[] intArray = {1, 2, 3};
String[] strArray = {"A", "B", "C"};
// 调用泛型方法。通常编译器可以推断出类型 T,无需显式指定
Utility.printArray(intArray); // T 被推断为 Integer
Utility.printArray(strArray); // T 被推断为 String
// 显式指定类型(不常用,通常在类型推断失败时使用)
Utility.<Integer>printArray(intArray);
Utility.printPair("Age", 25); // T 是 String, U 是 Integer
}
}
3.泛型接口
1.实现类给出具体类型
java
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
//3.泛型接口
public class list implements List<String> {
...
@Override
public boolean add(String s) {
return false;
}
...
}
java
list list2 = new list();
list2.add("hello");
list2.add("world");
System.out.println(list2);
2.实现类延续泛型,在创建实现类对象时再确定类型
java
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
public class list2<E> implements List<E> {
...
@Override
public boolean add(E e) {
return false;
}
...
}
java
list2<String> list3 = new list2<>();
list3.add("hello");
list3.add("world");
System.out.println(list3);
4.通配符
当方法中不确定使用什么类型的泛型时,使用通配符?
- ? extends E 表示泛型类型是E的子类
- ? super E 表示泛型类型是E的父类
- ? 表示任意类型