目录
一. ArrayList 基本介绍
二. ArrayList 中的法及其应用
1. 添加元素
(1) add()
(2) addAll()
2. 删除元素
(1) remove()
(2) removeAll()
3. 遍历元素
(1) for 循环遍历
(2) for - each 遍历
(3) 迭代器遍历
(4) 列表迭代器遍历
4. 判断
(1) cotains()
(2) containsAll()
(3) isEmpty()
5. 获取子列表
三. 模拟实现 ArrayList
1. 模拟实现添加元素
2. 模拟实现删除元素
3. 模拟实现判断
4. 验证是否正确
一. ArrayList 基本介绍
(1) ArrayList (顺序表) 继承于 List接口, 是Java集合框架的一部分.
(2) ArrayList 用于存放可重复, 有序的元素.
(3) ArrayList 的存储结构是数组. (底层使用数组来实现).
(4) ArrayList提供了比标准数组更多的功能. 例如: 动态调整大小, 添加元素, 删除元素等.
(5) ArrayList 的特点是 查找 的速度快 (因为可以直接通过下标查找), 添加/删除 元素的速度慢.
二. ArrayList 中的法及其应用
通过查看文档我们可以看到, List 接口主要有以上几种方法. 我把其中比较重要的几个方法勾选了出来, 这些我们要重点熟悉掌握. 大家也可以自行翻阅文档进行学习.
首先我们要在list里存放对象. 假设我们要存放Student类型的对象.
首先定义学生类:
public class Student {
private String name;
private int age;
public Student(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public int getAge() {
return age;
}
public void setName(String name) {
this.name = name;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
@Override
public boolean equals(Object obj) {
if (this == obj) { //1. 如果this和obj指向同一个对象, 则返回true;
return true;
}
if (obj instanceof Student) { //2. 如果this和obj指向不同对象, 而且obj是Student类型的
if (this.age == ((Student) obj).getAge() && this.name == ((Student) obj).getName()) {
return true;
}
return false;
}
return false;
}
}
1. 添加元素
(1) add()
add() 方法, 有两个版本: 版本一有一个参数, 版本二有两个参数.
[1] add(E e) 将指定元素添加到末尾
import java.util.ArrayList;
public class demo {
public static void main(String[] args) {
Student s1 = new Student("刘德华",22);
Student s2 = new Student("梁朝伟",24);
Student s3 = new Student("吴彦祖",26);
ArrayList<Student> arrayList = new ArrayList<>();
arrayList.add(s1);
arrayList.add(s2);
arrayList.add(s3);
System.out.println(arrayList);
}
}
[2] add(int index, E element) 将指定元素插入指定位置.
import java.util.ArrayList;
public class demo {
public static void main(String[] args) {
Student s1 = new Student("刘德华",22);
Student s2 = new Student("梁朝伟",24);
Student s3 = new Student("吴彦祖",26);
ArrayList<Student> arrayList = new ArrayList<>();
arrayList.add(s1);
arrayList.add(s2);
arrayList.add(s3);
System.out.println(arrayList);
Student s4 = new Student("Jack",45);
arrayList.add(1,s4);
System.out.println(arrayList);
}
}
(2) addAll()
addAll() 方法的基本作用是将一个列表添加到另一个列表中去. 与add() 类似, addAll() 方法也有两个版本:
[1] addAll(Collection e) 表示将另一列表添加到当前列表之后.
import java.util.ArrayList;
public class demo {
public static void main(String[] args) {
Student s1 = new Student("刘德华",22);
Student s2 = new Student("梁朝伟",24);
Student s3 = new Student("吴彦祖",26);
ArrayList<Student> arrayList = new ArrayList<>();
arrayList.add(s1);
arrayList.add(s2);
arrayList.add(s3);
System.out.println(arrayList); // 打印arrayList
Student s4 = new Student("Jack",45);
Student s5 = new Student("Bob", 55);
Student s6 = new Student("Molly",31);
ArrayList<Student> arrayList1 = new ArrayList<>();
arrayList1.add(s4);
arrayList1.add(s5);
arrayList1.add(s6);
System.out.println(arrayList1); // 打印arrayList1
arrayList.addAll(arrayList1);
System.out.println(arrayList); // 打印合并之后的arrayList
}
}
[2] addAll(intindex, Collection e) 表示在指定位置插入另一列表.
import java.util.ArrayList;
public class demo {
public static void main(String[] args) {
Student s1 = new Student("刘德华",22);
Student s2 = new Student("梁朝伟",24);
Student s3 = new Student("吴彦祖",26);
ArrayList<Student> arrayList = new ArrayList<>();
arrayList.add(s1);
arrayList.add(s2);
arrayList.add(s3);
System.out.println(arrayList);
Student s4 = new Student("Jack",45);
Student s5 = new Student("Bob", 55);
Student s6 = new Student("Molly",31);
ArrayList<Student> arrayList1 = new ArrayList<>();
arrayList1.add(s4);
arrayList1.add(s5);
arrayList1.add(s6);
System.out.println(arrayList1);
arrayList.addAll(1,arrayList1);
System.out.println(arrayList);
}
}
2. 删除元素
(1) remove()
remove() 方法, 参数可以传递下标, 也可以传递对象的引用. 作用都是把指定节点删除掉. 代码演示如下:
import java.util.ArrayList;
public class demo {
public static void main(String[] args) {
Student s1 = new Student("刘德华",22);
Student s2 = new Student("梁朝伟",24);
Student s3 = new Student("吴彦祖",26);
ArrayList<Student> arrayList = new ArrayList<>();
arrayList.add(s1);
arrayList.add(s2);
arrayList.add(s3);
System.out.println(arrayList);
arrayList.remove(0); // 传递下标删除元素
System.out.println(arrayList);
arrayList.remove(s2); // 传递对象删除元素
System.out.println(arrayList);
}
}
(2) removeAll()
与add()和addAll()的关系类似, remove()方法是删除单个元素, removeAll()方法是从一个列表里删除另一个列表中的所有元素.
因为我们在Student里重写了equals()方法, 所以只要两个对象的name和age属性一样, 那么就认为这两个对象是相同的.
import java.util.ArrayList;
public class demo {
public static void main(String[] args) {
Student s1 = new Student("刘德华",22);
Student s2 = new Student("梁朝伟",24);
Student s3 = new Student("吴彦祖",26);
ArrayList<Student> arrayList = new ArrayList<>();
arrayList.add(s1);
arrayList.add(s2);
arrayList.add(s3);
System.out.println(arrayList);
Student s4 = new Student("Jack",45);
Student s5 = new Student("Bob", 55);
Student s6 = new Student("Molly",31);
ArrayList<Student> arrayList1 = new ArrayList<>();
arrayList1.add(s1);
arrayList1.add(s2);
System.out.println(arrayList1);
arrayList.removeAll(arrayList1);
System.out.println(arrayList);
}
}
3. 遍历元素
(1) for 循环遍历
import java.util.ArrayList;
public class demo {
public static void main(String[] args) {
Student s1 = new Student("刘德华",22);
Student s2 = new Student("梁朝伟",24);
Student s3 = new Student("吴彦祖",26);
ArrayList<Student> arrayList = new ArrayList<>();
arrayList.add(s1);
arrayList.add(s2);
arrayList.add(s3);
for (int i = 0; i < arrayList.size(); i++) {
System.out.println(arrayList.get(i));
}
}
}
(2) for - each 遍历
import java.util.ArrayList;
public class demo {
public static void main(String[] args) {
Student s1 = new Student("刘德华",22);
Student s2 = new Student("梁朝伟",24);
Student s3 = new Student("吴彦祖",26);
ArrayList<Student> arrayList = new ArrayList<>();
arrayList.add(s1);
arrayList.add(s2);
arrayList.add(s3);
for (Student stu: arrayList) {
System.out.println(stu);
}
}
}
(3) 迭代器遍历
import java.util.ArrayList;
import java.util.Iterator;
public class demo {
public static void main(String[] args) {
Student s1 = new Student("刘德华",22);
Student s2 = new Student("梁朝伟",24);
Student s3 = new Student("吴彦祖",26);
ArrayList<Student> arrayList = new ArrayList<>();
arrayList.add(s1);
arrayList.add(s2);
arrayList.add(s3);
Iterator<Student> iterator = arrayList.iterator();
while (iterator.hasNext()) {
System.out.println(iterator.next());
}
}
}
(4) 列表迭代器遍历
- 正序遍历:
import java.util.ArrayList;
import java.util.Iterator;
import java.util.ListIterator;
public class demo {
public static void main(String[] args) {
Student s1 = new Student("刘德华",22);
Student s2 = new Student("梁朝伟",24);
Student s3 = new Student("吴彦祖",26);
ArrayList<Student> arrayList = new ArrayList<>();
arrayList.add(s1);
arrayList.add(s2);
arrayList.add(s3);
ListIterator<Student> iterator = arrayList.listIterator();
while (iterator.hasNext()) {
System.out.println(iterator.next());
}
}
}
- 逆序遍历:
import java.util.ArrayList;
import java.util.Iterator;
import java.util.ListIterator;
public class demo {
public static void main(String[] args) {
Student s1 = new Student("刘德华",22);
Student s2 = new Student("梁朝伟",24);
Student s3 = new Student("吴彦祖",26);
ArrayList<Student> arrayList = new ArrayList<>();
arrayList.add(s1);
arrayList.add(s2);
arrayList.add(s3);
ListIterator<Student> iterator = arrayList.listIterator(arrayList.size()); // 相当于把迭代器插入到 size() 位置的前面. 从这里开始遍历
while (iterator.hasPrevious()) {
System.out.println(iterator.previous());
}
}
}
[注]: 这里我们需要注意一点: 给 listIterator() 传参数 就表示将迭代器插入到index位置的前面.
所以这里给listIterator() 传了一个arrayList.size(), 就相当于把迭代器插入到了 size() 位置的前面
4. 判断
(1) cotains()
public class demo1 {
public static void main(String[] args) {
Student s1 = new Student("刘德华",22);
Student s2 = new Student("梁朝伟",24);
Student s3 = new Student("吴彦祖",26);
ArrayList<Student> arrayList = new ArrayList<>();
arrayList.add(s1);
arrayList.add(s2);
arrayList.add(s3);
System.out.println(arrayList.contains(new Student("吴彦祖", 26)));
System.out.println(arrayList.contains(new Student("周润发", 50)));
}
}
(2) containsAll()
import java.util.ArrayList;
import java.util.Iterator;
import java.util.ListIterator;
public class demo1 {
public static void main(String[] args) {
Student s1 = new Student("刘德华",22);
Student s2 = new Student("梁朝伟",24);
Student s3 = new Student("吴彦祖",26);
ArrayList<Student> arrayList = new ArrayList<>();
arrayList.add(s1);
arrayList.add(s2);
arrayList.add(s3);
ArrayList<Student> arrayList1= new ArrayList<>();
arrayList1.add(s1);
arrayList1.add(s2);
System.out.println(arrayList.containsAll(arrayList1));
}
}
(3) isEmpty()
判断当前顺序列表是否为空.
import java.util.ArrayList;
import java.util.Iterator;
import java.util.ListIterator;
public class demo1 {
public static void main(String[] args) {
Student s1 = new Student("刘德华",22);
Student s2 = new Student("梁朝伟",24);
Student s3 = new Student("吴彦祖",26);
ArrayList<Student> arrayList = new ArrayList<>();
arrayList.add(s1);
arrayList.add(s2);
arrayList.add(s3);
System.out.println(arrayList.isEmpty());
arrayList.clear();
System.out.println(arrayList.isEmpty());
}
}
5. 获取子列表
ArrayList中, 获取一个顺序列表的子列表, 需要使用 subList() 方法
subList() 方法, 参数传一个区间(左闭右开), 表示要获取的子列表的区间.
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
public class demo1 {
public static void main(String[] args) {
Student s1 = new Student("刘德华",22);
Student s2 = new Student("梁朝伟",24);
Student s3 = new Student("吴彦祖",26);
Student s4 = new Student("大师",99);
ArrayList<Student> arrayList = new ArrayList<>();
arrayList.add(s1);
arrayList.add(s2);
arrayList.add(s3);
arrayList.add(s4);
System.out.println(arrayList);
List<Student> sl = arrayList.subList(1,3); //获取区间[1,3) 左闭右开.
System.out.println(sl);
}
}
6. 获取下标
ArrayList中, 获取下标使用 indexOf() 方法:
public class demo2 {
public static void main(String[] args) {
Student s1 = new Student("刘德华",22);
Student s2 = new Student("梁朝伟",24);
Student s3 = new Student("吴彦祖",26);
Student s4 = new Student("大师",99);
ArrayList<Student> arrayList = new ArrayList<>();
arrayList.add(s1);
arrayList.add(s2);
arrayList.add(s3);
arrayList.add(s4);
System.out.println(arrayList.indexOf(s2));
System.out.println(arrayList.indexOf(s3));
}
}
三. 模拟实现 ArrayList
我们知道, Arraylist底层是基于数组实现的. 所以, 我们在模拟实现Arraylist的时候,, 就需要先创建于一个数组, 然后基于数组实现我们自己的Arraylist.
为了实现起来简单, 我们自己实现ArrayList只能存放 int 类型的元素.
public class MyArrayList {
public int[] elem; //定义一个操作数组
public int usedSize; //定义一个 "已使用空间"
public MyArrayList() {
this.elem = new int[10];
}
}
如上图, 这是就是模拟顺序列表中的属性, 一个是数组elem(在创建对象时 被初始化为10) , 另一个是usedSize, 表示已使用空间 (也就是数组中的元素个数 / 数组的长度).
还有一个问题, 因为我们验证我们写的方法是否正确时 要打印数组, 所以我们还需要重写一下 toString 方法, 否则打印出来的一堆哈希码, 没有可读性.
@Override
public String toString() {
String str = "";
for (int i = 0; i < size(); i++) {
if (i == 0){
str += "[";
str += elem[i];
str += ",";
continue;
}
if (i == size()-1) {
str += elem[i];
str += "]";
continue;
}
str += elem[i];
str += ",";
}
return str;
}
1. 模拟实现添加元素
判满方法:
private boolean isFull () {
if (usedSize == elem.length) {
return true;
}
else {
return false;
}
}
(1) 添加元素到末尾
public void add(int data) { //添加元素到末尾.
if (this.isFull()) { //如果数组满了, 对数组进行扩容.
elem = Arrays.copyOf(elem, 2*elem.length);
}
elem[usedSize] = data;
usedSize ++;
}
先判断数组是不是满了: 如果满了, 就扩容; 如果没满, 就进行添加元素操作.
(2) 添加元素到指定位置
public void add(int index, int data) { // 添加元素到指定位置.
if (this.isFull()) {
elem = Arrays.copyOf(elem, 2*elem.length);
}
for (int i = size()-1; i >= index; i--) {
elem[i+1] = elem[i]; // 把元素向后移一位.(把i位置的元素赋到它后面的位置)
}
elem[index] = data;
usedSize++;
}
相同地, 我们还是先判断是不是数组满的: 如果满了, 就扩容; 如果没满, 就进行添加元素操作.
这里由于是添加到指定位置, 所以原先在指定位置的元素及其后面的所有元素就需要后移.
2. 模拟实现删除元素
获取列表长度方法:
public int size() { // 求当前顺序表的长度.
return this.usedSize;
}
(1) 根据值删除元素
public void remove (int data) { //根据值删除元素
for (int i = 0; i < size(); i++) { //先找到指定元素的下标
if (elem[i] == data) {
for (int j = i; j < size()-1; j++) {
elem[j]= elem[j+1]; // 往前覆盖掉elem[i].
}
usedSize--;
}
}
}
这里需要注意的点是: 删除元素 就是把指定元素的位置覆盖掉就可以了.
(2) 根据下标删除元素
public void removeIndex (int index) { // 根据下标删除元素
for (int j = index; j < size()-1; j++) {
elem[j] = elem[j+1];
}
usedSize--;
}
3. 模拟实现判断
(1) contains
public boolean contains(int data) { // 判断是否包含指定元素data
for (int i = 0; i < size(); i++) {
if (elem[i] == data) {
return true;
}
}
return false;
}
(2) isEmpty()
public boolean isEmpty() { //判断当前顺序列表是否为空
if (this.usedSize == 0) {
return true;
}
else {
return false;
}
}
(3) clear()
public void clear() { // 清空当前顺序列表.
this.usedSize = 0;
}
4. 验证是否正确
public class Main {
public static void main(String[] args) {
MyArrayList myArrayList = new MyArrayList();
//1. 验证add (添加到元素末尾)
myArrayList.add(1);
myArrayList.add(1);
myArrayList.add(2);
myArrayList.add(3);
myArrayList.add(4);
myArrayList.add(5);
System.out.println(myArrayList);
//2. 验证 add (添加到指定位置)
myArrayList.add(2,99);
System.out.println(myArrayList);
//3. 验证 remove (根据值删除元素)
myArrayList.remove(2);
System.out.println(myArrayList);
//4. 验证 remove (根据下标删除元素)
myArrayList.removeIndex(1);
System.out.println(myArrayList);
//5. 验证 contains
System.out.println(myArrayList.contains(99));
//6. 验证 isEmpty() 和 clear()
System.out.println(myArrayList.isEmpty());
myArrayList.clear();
System.out.println(myArrayList.isEmpty());
}
}
通过打印结果我们发现, 我们模拟实现的 ArrayList 没有任何问题~~