一.为什么要用ArrayList?
数组是一个重要的数据数据结构,但它有一个明显的缺点,长度一旦设定将不可以改变。ArrayList的底层也是用数组实现,所以它拥有数组的优点,方便查询等,但ArrayList的数组长度可以改变,也被称为动态数组。
二.ArrayList的源码解析
2.1属性和构造方法
public class ArrayList<E> extends AbstractList<E>
implements List<E>, RandomAccess, Cloneable, java.io.Serializable
ArrayList是AbstractList的子类,AbstractList是一个抽象类。ArraList的接口有List,RandomAccess,Serializable.
@java.io.Serial
private static final long serialVersionUID = 8683452581122892189L;
版本信息
private static final int DEFAULT_CAPACITY = 10;
初始容量
private static final Object[] EMPTY_ELEMENTDATA = {};
空的数组
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
缺省空对象数组
transient Object[] elementData;
元素数组
private int size;
实际数据元素的个数
public ArrayList(int initialCapacity) {
if (initialCapacity > 0) {
this.elementData = new Object[initialCapacity];
} else if (initialCapacity == 0) {
this.elementData = EMPTY_ELEMENTDATA;
} else {
throw new IllegalArgumentException("Illegal Capacity: "+
initialCapacity);
}
}
有参构造方法,有于自定义数组容量大小。大于0,将初始容量大小设为 initialCapacity。
等于0,就为空数组。小于0,抛出异常。
public ArrayList() {
this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}
无参构造方法,元素数组等于空的对象数组。
2.2核心方法
private void add(E e, Object[] elementData, int s) {
if (s == elementData.length)
elementData = grow();
elementData[s] = e;
size = s + 1;
}
如果传入的参数s等于元素数组的长度,就进行扩容,并把e元素传入元素数组下标为s的位置。下面我们看ArrayList的核心中的核心,扩容机制grow方法。
private Object[] grow(int minCapacity) {
int oldCapacity = elementData.length;
if (oldCapacity > 0 || elementData != DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
int newCapacity = ArraysSupport.newLength(oldCapacity,
minCapacity - oldCapacity, /* minimum growth */
oldCapacity >> 1 /* preferred growth */);
return elementData = Arrays.copyOf(elementData, newCapacity);
} else {
return elementData = new Object[Math.max(DEFAULT_CAPACITY, minCapacity)];
}
}
传入一个最小容量。把元素数组的长度给oldCapacity(老容量),如果老容量大于0或者元素数组不等于缺省空对象数组,则第一个newCapacity(新容量),变为原来长度的1.5倍,把元素数组的容量改为新容量并返回,否则把10和最小容量比较,大的容量给元素数组。
public boolean add(E e) {
modCount++;
add(e, elementData, size);
return true;
}
在元素数组的末尾添元素。
public void add(int index, E element) {
rangeCheckForAdd(index);
modCount++;
final int s;
Object[] elementData;
if ((s = size) == (elementData = this.elementData).length)
elementData = grow();
System.arraycopy(elementData, index,
elementData, index + 1,
s - index);
elementData[index] = element;
size = s + 1;
}
在指定索引位置添加元素。先判断index的是否是正确的不正确抛出异常。定义一个整形s和一个元素数组。把size赋值给s,s如果等于元素数组长度,进行扩容。并把插入后面的元素下标加一。
public E remove(int index) {
Objects.checkIndex(index, size);
final Object[] es = elementData;
@SuppressWarnings("unchecked") E oldValue = (E) es[index];
fastRemove(es, index);
return oldValue;
}
指定位置删除,删除是每次进行数组复制,然后让旧的elementData置为null进行垃圾回收。
三.ArrayList的简单实在。
package Underlyingcode;
import java.io.PrintStream;
import java.util.Arrays;
public class MyArrayList {
private static final int d=10;
private static final Object [] a= {};//空元素数据 EMPTY_ELEMENTDATA
private static final Object [] b= {};//违约元素数据 DEFAULTCAPACITY_EMPTY_ELEMENTDATA
private static Object [] c= {};//元素数据 elementData
private int size=0;
public MyArrayList() {
this.c=new Object[d];
}
//initialCapacity 初始容量
public MyArrayList(int size) throws Exception{
if(size > 0)
this.c = new Object[size];
else
throw new Exception("长度不允许小于零!");
}
//增加元素
public void add(Object number) {
if(size>=c.length) {
Object [] zj =new Object[c.length];
for(int i=0;i<c.length;i++) {
zj[i]=c[i];
}
int length=c.length+c.length/2;
c=new Object[length];
for(int j=0;j<zj.length;j++) {
c[j]=zj[j];
}
zj = null;
}
c[size]=number;
size++;
}
//获取值
public Object get(int index) {
if(index<0||index>size) {
throw new ArrayIndexOutOfBoundsException("你乱输入索引");
}
return c[index];
}
// 搜索给定参数第一次出现的位置,使用 equals 方法进行相等性测试。
public int indexof(Object a) {
int i;
for(i=0;i<c.length;i++) {
if(a.equals(c[i])) {
return i;
}
}
if(i==c.length) {
return -1;
}
return 0;
}
// 移除此列表中指定位置上的元素.向左移动所有后续元素(将其索引减 1)。
public void remove(int indenx) {
if(c[indenx]==null) {
System.out.println("这个索引对应的数据没有值");
}else {
for(int i=indenx;i<size;i++) {
c[i]=c[i+1];
}
}
}
//测试此列表中是否没有元素。
public boolean isEmpty() {
if(size==0) {
return false;
}else {
return true;
}
}
public static void main(String[]args) {
MyArrayList a=new MyArrayList();
a.add(1);
a.add(2);
a.add(3);
a.add(null);
a.add(3);
a.add(3);
a.add(3);
a.add(3);
a.add(3);
a.add(3);
a.add(10);
System.out.println(a.isEmpty());
System.out.println(Arrays.toString(c));
System.out.println(a.indexof(3));
System.out.println(a.get(4));
a.remove(4);
System.out.println(Arrays.toString(c));
}
}
运行结构
总结
ArrayList建立的空间是连续的,方便查询,但不方便删除和添加。注意ArrayLIst是不同步的,所以是不安全的。