集合
集合是一个可以存放引用数据类型的容器,大小不固定。 集合的顶级接口是Collection
<E>``` :泛型,就是集合中存放的数据类型。只能是引用数据类型,不能是基本数据类型
## 集合特点
提供一种存储空间可变的存储模型,存储数据的容量可以发生改变
在数组装满的情况下 自动扩容
1.数组
2.链表
3.树
4.队列
## 集合常用方法
```java
import java.util.ArrayList;
import java.util.Collection;
public static void main(String[] args) {
//ArrayList<>()方法
Collection
<String> collection = new ArrayList<>();
//添加元素
collection.add("123");
collection.add("456");
//清空集合
collection.clear();
//判断是否包含某一元素
//contains()
System.out.println(collection.contains("123"));
System.out.println(collection);
//判断集合是否为空
//isEmpty()
System.out.println(collection.isEmpty());
//获取集合中的元素个数
System.out.println(collection.size());
//把集合转换成数组
Object[] objects = collection.toArray(new String[0]);
for (String object : objects) {
System.out.println(object);
}
System.out.println(collection);
}
List 接口
特点:
- 有序
- 可以存放重复的元素
- 方法中有索引
import java.util.ArrayList;
public static void main(String[] args) {
//List接口
List
<String> list = new ArrayList<>();
//添加数据
list.add("java");
//插入元素
list.add(2, "JAVA");
//根据索引获取元素
String s = list.get(3);
System.out.println(s);
//获取元素首次出现的索引
int index = list.indexOf("java");
System.out.println(index);
//获取元素最后一次出现的索引
int JAVA = list.lastIndexOf("JAVA");
System.out.println(JAVA);
//根据索引删除元素
String remove = list.remove(2);
System.out.println(remove);
//修改给出索引处的元素
list.set(2, "C++");
//截取子列表 包头不包尾
List
<String> strings = list.sublist(1, 2);
System.out.println(strings);
System.out.println(list);
}
ArrayList
JDK封装好的ArrayList/Map/Set
原生数组存放数据 在开始定义时容量固定 因此会无法存放
特点:
底层的数据结构是数组,因此内存是连续的
ArrayList的查询速度相对更快
ArrayList的增加和删除速度相对慢
ArrayList是线程不安全的集合
调用无参构造,会创建一个长度为0的Object类型的数组
当第一次调用add方法时,会创建一个长度为10的数组。
ArrayList默认内容是10
扩容 = 原本容量 + 原本容量 / 2
当调用有参构造指定初始化容量时,指定多少就是多少
实例
import java.util.ArrayList;
public class TestDemo {
public static void main(String[] args) {
/**
* new ArrayList<泛型>
*/
list
<String> arrayList = new ArrayList<String>();//集合容器中只能存入 String 类型
//arrayList 对象名称
arrayList.add("mayikt");
}
}
方法实例
import java.util.ArrayList;
public static void main(String[] args) {
// list接口
List
<String> list = new ArrayList<>(16);
//添加数据
list.add("java");
list.add("C");
list.add("C#");
list.add(".net");
list.add("golang");
list.add("python");
list.add("python");
//插入元素
list.add(2, "PHP");
//根据索引获取元素
String s = list.get(3);
System.out.println(s);
//获取元素首次出现的索引
int index = list.indexOf("丁真");
System.out.println(index);
// 获取元素最后一次出现的索引
int python = list.lastIndexOf("python");
System.out.println(python);
// 根据索引删除元素
String remove = list.remove(2);
System.out.println(remove);
// 修改指定索引处的元素
list.set(1, "怪0");
// 截取子列表 包头不包尾
List
<String> strings = list.subList(1, 5);
System.out.println(strings);
System.out.println(list);
}
功能实现
实现ArrayList
import java.util.Arrays;
public class ArrayListDemo {
private String[] data;
private int size = 0;
public ArrayListDemo() {
data = new String[0];
}
private void grow() {
if (data.length == 1) {
data = Arrays.copyOf(data, data.length + 1);
} else data = Arrays.copyOf(data, data.length + (data.length >> 1));
}
private void isIndexOutOfBound(int index) {
if (index < 0 || index >= data.length) throw new IndexOutOfBoundsException();
}
/*
* 添加元素
* */
public void add(String str) {
if (data.length == 0) data = new String[10];
//判断是否需要扩容
if (size >= data.length) {
grow();
}
data[size] = str;
size++;
}
/*
* 插入元素
* */
public void insert(int index, String str) {
//判断索引是否越界
isIndexOutOfBound(index);
//判断是否需要扩容
//两种情况,插入在数组内,插入在数组最后一个
if (size >= data.length) {
grow();
}
//方法一 循环
// for(int i = 0; i < size; i++) {
// data[i+1] = data[i];
// }
//方法二 arraycopy()
System.arraycopy(data, index, data, index + 1, size - index);
data[index] = str;
size++;
}
//删除指定元素
public void remove(int index) {
//判断索引是否越界
isIndexOutOfBound(index);
//方式一 循环
// for (int i = 0; i < index; i++) {
// data[i] = data[i + 1];
// }
//方法二 arraycopy()
System.arraycopy(data, index + 1, data, index, size - index - 1);
size--;
}
@Override
public String toString() {
StringBuffer stringBuffer = new StringBuffer();
stringBuffer.append("[");
for (int i = 0; i < size; i++) {
if (i != size - 1) stringBuffer.append(data[i]).append(",");
else {
stringBuffer.append(data[i]);
}
}
stringBuffer.append("]");
return stringBuffer.toString();
}
}
LinkedList
- LinkedList底层数据结构是双向不循环链表
- LinkedList的内存是不连续的
- LinkedList查询相对慢
- LinkedList增删相对快
- LinkedList线程不安全
实现LinkedList
import java.util.Objects;
public class LinkedListDemo {
private int size;
private Node first;
private Node last;
private class Node {
String item;
Node next;
Node prev;
public Node(String item, Node next, Node prev) {
this.item = item;
this.next = next;
this.prev = prev;
}
}
private void isIndexOutOfBound(int index) {
if (index > size || index < 0) throw new IndexOutOfBoundsException();
}
private Node getNode(int index) {
Node targetNode = first;
for (int i = 0; i < index; i++) {
targetNode = targetNode.next;
}
return targetNode;
}
/*
* 添加元素方法
* */
public void addNode(String str) {
//添加元素分两种情况
//1. 第一次添加,头结点和尾结点相同
//2. 第n次添加,需要把新添加的结点设为尾结点
//创建结点
Node node = new Node(str, null, null);
if (size == 0) {
first = node;
} else {
last.next = node;
}
last = node;
size++;
}
/*
* 插入元素
* @param index 插入的索引
* @param str 插入的内容
* */
public void insert(int index, String str) {
//判断索引是否越界
isIndexOutOfBound(index);
//双向链表插入分三种情况,头部,中间,尾部
//插入尾部
if (index == size) {
addNode(str);
}
Node newnode = new Node(str, null, null);
if (size == 0) {
//插入头部
newnode.next = first;
first.prev = newnode;
first = newnode;
} else {
//插入中间,需要先寻找索引处的结点
//通过封装好的方法,遍历链表找到对应需要插入的结点位置
Node nextnode = getNode(index);
//找到的后结点指向的前结点的后结点为新结点
nextnode.prev.next = newnode;
//新结点指向的前结点为前结点
newnode.prev = nextnode.prev;
//新节点指向的后结点为后结点
newnode.next = nextnode;
//后结点指向的前结点为新结点
nextnode.prev = newnode;
}
size++;
}
//删除元素
public void remove(int index) {
isIndexOutOfBound(index);
//删除元素分三种情况,删除头节点 尾结点 中间结点
//删除头部结点
if (index == 0) {
first = first.next;
first.prev = null;
}
//删除尾部结点
else if (index == size - 1) {
last = last.prev;
last.next = null;
}
//删除中间结点
else {
Node targetNode = getNode(index);
targetNode.prev.next = targetNode.next;
targetNode.next.prev = targetNode.prev;
}
size--;
}
/*
* 查询指定元素首次出现的索引
* 按字符串查找
* */
public int indexOf(String str) {
Node node = first;
for (int i = 0; i < size; i++) {
if (Objects.equals(node.item, str))
return i;
node = node.next;
}
return -1;//如果未找到返回-1
}
/*
*删除指定元素
* 调用查找指定元素的方法
* 调用删除元素的方法
* */
public void remove(String str) {
int i = indexOf(str);
if (i != -1) {
remove(i);
}
}
/*
* 判断链表中是否包含某元素
* */
public boolean contains(String str) {
return indexOf(str) != -1;
}
}
LinkedList的增删改查操作图解
个人理解
主要思想是利用找到的新结点的后结点的指针定位新结点的前结点


![第3步.png](https://www.neet0316.com/wp-content/uploads/2025/12/%E7%AC%AC3%E6%AD%A5.png
![第4步.png](https://www.neet0316.com/wp-content/uploads/2025/12/%E7%AC%AC4%E6%AD%A5.png