文章目录
一、简介
ArrayList
类是一个可以动态修改的数组,与普通数组的区别就是它是没有固定大小的限制,我们可以添加或删除元素。
ArrayList
继承了 AbstractList
,并实现了 List
接口。
ArrayList
类位于 java.util
包中,使用前需要引入它,语法格式如下:
import java.util.ArrayList; // 引入 ArrayList 类
ArrayList<E> objectName =new ArrayList<>(); // 初始化
- E: 泛型数据类型,用于设置
objectName
的数据类型,只能为引用数据类型。 - objectName: 对象名。
注:
ArrayList
实现了RandomAccess
接口,表明ArrayList
支持随机访问。ArrayList
实现了Cloneable
接口,表明ArrayList
是可以clone的。ArrayList
实现了Serializable
接口,表明ArrayList
是支持序列化的。- 和
Vector
不同,ArrayList
不是线程安全的,在单线程下可以使用,在多线程中可以选择Vector
或者CopyOnWriteArrayList
。 ArrayList
底层是一段连续的空间,并且可以动态扩容,是一个动态类型的顺序表。
二、使用
1、构造
ArrayList有三种构造方式:无参构造、利用其他的collection构造、指定顺序表的初始容量。
1.1 无参构造
无参构造类型是推荐的写法。
//Integer为整型的包装类型
List<Integer> list = new ArrayList<>();
1.2 指定初始容量
List<Integer> list = new ArrayList<>(10);
list.add(1);
list.add(2);
list.add(3);
1.3 利用其他的collection进行构造
//构建一个与list1元素一样的list
ArrayList<Integer> list2 = new ArrayList<>(list1);
注: 无论哪种构造形式,都应该避免省略类型,任意类型的元素都能够存放,使用时会带来很多麻烦。
2、基础操作
2.1 添加元素
添加元素到 ArrayList
可以使用 add()
方法:
public class Test{
public static void main(String[] args) {
ArrayList<String> array = new ArrayList<String>();
sites.add("Hello");
sites.add("CSDN");
System.out.println(array);
}
}
2.2 删除元素
删除元素使用remove()
方法:
public class Test {
public static void main(String[] args) {
ArrayList<String> array = new ArrayList<>();
array.add("Hello");
array.add("CSDN");
array.add("IDEA");
array.add("Java");
System.out.println(array);
array.remove(2);
System.out.println(array);
}
}
2.3 修改元素
修改元素可以使用 set()
方法:
public class Test {
public static void main(String[] args) {
ArrayList<String> array = new ArrayList<>();
array.add("Hello");
array.add("CSDN");
array.add("IDEA");
array.add("Java");
System.out.println(array);
array.set(2,"python"); // 第一个参数为索引,第二个参数为要修改的值
System.out.println(array);
}
}
2.4 访问元素
访问元素使用get()方法:
public class Test {
public static void main(String[] args) {
ArrayList<String> array = new ArrayList<>();
array.add("Hello");
array.add("CSDN");
array.add("IDEA");
array.add("Java");
System.out.println(array);
System.out.println(array.get(2)); // 获取位置2的元素
}
}
2.5 计算大小
计算数组内元素个数使用size()
方法:
public class Test {
public static void main(String[] args) {
ArrayList<String> array = new ArrayList<>();
array.add("Hello");
array.add("CSDN");
array.add("IDEA");
array.add("Java");
System.out.println(array);
System.out.println(array.size());
}
}
2.6 遍历数组
遍历数组有三种方式:for循环遍历、for-each遍历、迭代器遍历。
public class Test {
public static void main(String[] args) {
ArrayList<String> array = new ArrayList<>();
array.add("Hello");
array.add("CSDN");
array.add("IDEA");
array.add("Java");
System.out.println(array);
System.out.println("for:");
for (int i = 0; i < array.size(); i++) {
System.out.print(array.get(i)+" ");
}
System.out.println();
System.out.println("for-each:");
for (String j:array) {
System.out.print(j+" ");
}
System.out.println();
System.out.println("迭代器:");
Iterator<String> it = array.listIterator();
while(it.hasNext()){
System.out.print(it.next() + " ");
}
System.out.println();
}
3、常用操作
方法 | 作用 |
---|---|
void add(int index, E element) | 将element元素插入到index位置 |
boolean addAll(Collection<? extends E> c) | 将c中的元素全部插入 |
boolean remove(Object o) | 删除第一个遇到的o元素 |
void clear() | 清空 |
boolean contains(Object o) | 判断o是否在表中 |
int indexOf(Object o) | 返回第一个o所在的下标 |
int lastIndexOf(Object o) | 返回最后一个o的下标 |
List<E> subList(int fromIndex, int toIndex) | 截取fromindex到toindex的元素 |
public class Test {
public static void main(String[] args) {
ArrayList<String> array = new ArrayList<>();
ArrayList<String> array2 = new ArrayList<>();
array.add("Hello");
array.add("CSDN");
array.add("Java");
array.add("IDEA");
array2.add("python");
array2.add("Java");
array.add(1,"Data");
System.out.println("array = " + array);
array2.addAll(array);
System.out.println("array2 = " + array2);
array2.remove("Data");
System.out.println("array2 = " + array2);
array.clear();
System.out.println("array = " + array);
System.out.println("Java是否在表中:" + array2.contains("Java"));
System.out.println("array2.indexOf(\"Java\") = " + array2.indexOf("Java"));
System.out.println("array2.lastIndexOf(\"Java\") = " + array2.lastIndexOf("Java"));
System.out.println("array2.subList(1,4) = " + array2.subList(1,4));
}
4、扩容机制
ArrayList是一个动态类型的顺序表,即,在插入元素的过程中会自动扩容:
Object[] elementData; // 存放元素的空间
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {}; // 默认空间
private static final int DEFAULT_CAPACITY = 10; // 默认容量大小
public void ensureCapacity(int minCapacity) {
// 计算最小的扩容大小
int minExpand = (elementData != DEFAULTCAPACITY_EMPTY_ELEMENTDATA)? 0 :
DEFAULT_CAPACITY;
// 检测是否需要扩容
if (minCapacity > minExpand) {
ensureExplicitCapacity(minCapacity);
}
}
private void ensureExplicitCapacity(int minCapacity) {
modCount++;
// 如果minCapacity比数组的容量大,就调用grow进行扩容
if (minCapacity - elementData.length > 0)
grow(minCapacity);
}
private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
private void grow(int minCapacity) {
// 获取旧空间大小
int oldCapacity = elementData.length;
// 预计按照1.5倍方式扩容
int newCapacity = oldCapacity + (oldCapacity >> 1);
// 如果用户需要扩容大小超过原空间1.5倍,按照用户所需大小扩容
if (newCapacity - minCapacity < 0)
newCapacity = minCapacity;
// 如果需要扩容大小超过MAX_ARRAY_SIZE,重新计算容量大小
if (newCapacity - MAX_ARRAY_SIZE > 0)
newCapacity = hugeCapacity(minCapacity);
// 调用copyOf扩容
elementData = Arrays.copyOf(elementData, newCapacity);
}
private static int hugeCapacity(int minCapacity) {
// 如果minCapacity小于0,抛出OutOfMemoryError异常
if (minCapacity < 0)
throw new OutOfMemoryError();
return (minCapacity > MAX_ARRAY_SIZE) ? Integer.MAX_VALUE : MAX_ARRAY_SIZE;
}
三、模拟实现ArrayList
为了更好的理解和使用ArrayList,对其进行了模拟实现
之前单独写过一篇博客进行模拟:Java——模拟实现ArrayList(动态数组)