ArrayList
ArrayList
说明
ArrayList是List的一个实现类,底层是数组,查询快,增删慢,线程不安全
实践
class Student {
String name;
Integer age;
public Student() {
}
public Student(String name, Integer age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public Integer getAge() {
return age;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", 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 Objects.equals(name, student.name) && Objects.equals(age, student.age);
}
@Override
public int hashCode() {
return Objects.hash(name, age);
}
}
package com.qianfeng.collection;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.ListIterator;
/**
* 功能描述
*
* @since 2022-05-07
*/
public class ArrayListDemo {
public static void main(String[] args) {
ArrayList<Object> arrayList = new ArrayList<>();
Student s1 = new Student("张三", 10);
Student s2 = new Student("李四", 11);
Student s3 = new Student("王五", 12);
// 添加元素
arrayList.add(s1);
arrayList.add(s2);
arrayList.add(s3);
arrayList.add(s3);
System.out.println(arrayList);
// 删除元素
arrayList.remove(new Student("李四", 11));
System.out.println(arrayList);
//遍历
System.out.println("==============迭代器遍历================");
Iterator it = arrayList.iterator();
while (it.hasNext()) {
System.out.println(it.next());
}
System.out.println("==============迭代器遍历================");
ListIterator lit = arrayList.listIterator();
while (lit.hasNext()) {
System.out.println(lit.next());
}
System.out.println("==============迭代器遍历逆序================");
while (lit.hasPrevious()) {
System.out.println(lit.previous());
}
//判断
System.out.println(arrayList.isEmpty());
System.out.println(arrayList.contains(new Student("王五", 12)));
//定位
System.out.println(arrayList.indexOf(new Student("王五", 12)));
}
}
源码分析
带着疑问看源码
1.ArrayList底层是数组,数组的大小在初始化的时候确定,初始的尺寸如何确定?扩容如何实现?缩容呢?
数组的大小即容量
容量:
当ArrayList中没有数据时,容量为0,添加一个数据后,容量为10,元素数量超出容量后进行扩容,每次扩容为原来的1.5倍
初始参数
DEFAULT_CAPACITY = 10; //初始容量是10
transient Object[] elementData; //数据最终存储在该数组内
private int size; // ArrayList包含元素的个数
arrayList.add()源码分析
public boolean add(E e) {
ensureCapacityInternal(size + 1); // Increments modCount!!
elementData[size++] = e;
return true;
}
private void ensureCapacityInternal(int minCapacity) {
ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
}
private static int calculateCapacity(Object[] elementData, int minCapacity) {
if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
return Math.max(DEFAULT_CAPACITY, minCapacity);
}
return minCapacity;
}
private void ensureExplicitCapacity(int minCapacity) {
modCount++;
// overflow-conscious code
if (minCapacity - elementData.length > 0)
grow(minCapacity);
}
// 扩容的核心代码
private void grow(int minCapacity) {
// overflow-conscious code
int oldCapacity = elementData.length;
// 扩容每次扩原来容量的1.5倍
int newCapacity = oldCapacity + (oldCapacity >> 1);
// 首次扩容时扩容到10
if (newCapacity - minCapacity < 0)
newCapacity = minCapacity;
if (newCapacity - MAX_ARRAY_SIZE > 0)
newCapacity = hugeCapacity(minCapacity);
// minCapacity is usually close to size, so this is a win:
// 将原数组复制到新的长度的数组中
elementData = Arrays.copyOf(elementData, newCapacity);
}
remove方法源码分析
看完源码可以得出 ArrayList没有自动缩容的机制,想要缩容需要手动调用trimToSize方法
public E remove(int index) {
// index范围检查
rangeCheck(index);
modCount++;
E oldValue = elementData(index);
int numMoved = size - index - 1;
// 调用本地方法实现数组的拷贝,将index+1及后面的元素移动到index处
if (numMoved > 0)
System.arraycopy(elementData, index+1, elementData, index,
numMoved);
elementData[--size] = null; // clear to let GC do its work
return oldValue;
}
trimToSize 手动缩容即直接缩容至当前集合包含的元素个数
public void trimToSize() {
modCount++;
if (size < elementData.length) {
elementData = (size == 0)
? EMPTY_ELEMENTDATA
: Arrays.copyOf(elementData, size);
}
}