ArrayList源码分析,你需要知道的所有知识点!("全面解析ArrayList源码:掌握核心知识点必备指南!")

原创
ithorizon 6个月前 (10-20) 阅读数 22 #后端开发

全面解析ArrayList源码:掌握核心知识点必备指南!

一、ArrayList简介

ArrayList是Java中非常常用的一个类,它实现了List接口,是基于动态数组的数据结构。ArrayList允许包含重复的元素,它的容量是可以采取需求动态增长的。相较于LinkedList,ArrayList在随机访问元素时具有更高的高效,但在插入和删除元素时性能稍逊一筹。

二、ArrayList的核心成员变量

ArrayList的核心成员变量包括:

  • transient Object[] elementData;
  • private int size;

其中,elementData 是存储元素的数组,size 是数组中元素的数量。

三、ArrayList的构造方法

ArrayList提供了三种构造方法:

public ArrayList(int initialCapacity) {

if (initialCapacity >= 0) {

this.elementData = new Object[initialCapacity];

} else {

throw new IllegalArgumentException("Illegal Capacity: " +

initialCapacity);

}

}

public ArrayList() {

this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;

}

public ArrayList(Collection c) {

elementData = c.toArray();

if ((size = elementData.length) != 0) {

// c.toArray might (incorrectly) not return Object[]

// array with 0 length; check for it.

if (elementData.getClass() != Object[].class)

elementData = Arrays.copyOf(elementData, size);

} else {

// replace with empty array.

this.elementData = EMPTY_ELEMENTDATA;

}

}

其中,DEFAULTCAPACITY_EMPTY_ELEMENTDATA 是一个空的数组,用于无参构造方法,默认初始容量为10。

四、ArrayList的扩容机制

当ArrayList中的元素数量约为当前数组的容量时,会进行扩容操作。扩容操作的核心代码如下:

private void ensureCapacityInternal(int minCapacity) {

if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {

minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);

}

if (minCapacity - elementData.length > 0)

grow(minCapacity);

}

private void grow(int minCapacity) {

// overflow-conscious code

int oldCapacity = elementData.length;

int newCapacity = oldCapacity + (oldCapacity >> 1); // 扩容为原来的1.5倍

if (newCapacity - minCapacity < 0)

newCapacity = minCapacity;

if (newCapacity - MAX_ARRAY_SIZE > 0)

newCapacity = hugeCapacity(minCapacity);

elementData = Arrays.copyOf(elementData, newCapacity);

}

从代码中可以看出,ArrayList的扩容操作会将数组容量提高为原来的1.5倍。如果扩容后的容量仍然小于所需的最小容量,则将容量调整为最小容量。如果扩容后的容量超过了最大数组容量,则调用hugeCapacity方法处理。

五、ArrayList的添加元素方法

ArrayList提供了多种添加元素的方法,如add(E e)add(int index, E element)等。以下是add(E e)方法的源码:

public boolean add(E e) {

ensureCapacityInternal(size + 1); // 确保数组有足够空间

elementData[size++] = e; // 添加元素到数组末尾

return true;

}

该方法首先调用ensureCapacityInternal(size + 1)确保数组有足够的空间,然后将元素添加到数组末尾,并更新数组大小。

六、ArrayList的删除元素方法

ArrayList提供了多种删除元素的方法,如remove(int index)remove(Object o)等。以下是remove(int index)方法的源码:

public E remove(int index) {

if (index >= size || index < 0)

throw new IndexOutOfBoundsException(outOfBoundsMsg(index));

E oldValue = (E) elementData[index];

int numMoved = size - index - 1;

if (numMoved > 0)

System.arraycopy(elementData, index+1, elementData, index,

numMoved);

elementData[--size] = null; // clear to let GC do its work

return oldValue;

}

该方法首先检查索引是否越界,然后保存要删除的元素,接着将索引后的元素向前移动,最后将数组最后一个元素设置为null,以便垃圾回收器回收。

七、ArrayList的遍历方法

ArrayList提供了多种遍历方法,如for循环、for-each循环、迭代器等。以下是使用for循环遍历ArrayList的示例代码:

ArrayList list = new ArrayList<>();

list.add(1);

list.add(2);

list.add(3);

for (int i = 0; i < list.size(); i++) {

System.out.println(list.get(i));

}

当然,也可以使用Java 8的Stream API进行遍历:

ArrayList list = new ArrayList<>();

list.add(1);

list.add(2);

list.add(3);

list.stream().forEach(System.out::println);

八、ArrayList的线程保险性

ArrayList不是线程保险的,如果多个线程同时访问ArrayList,必须进行同步处理。以下是使用同步代码块来保证ArrayList线程保险的示例代码:

ArrayList list = new ArrayList<>();

list.add(1);

list.add(2);

list.add(3);

synchronized (list) {

for (Integer num : list) {

System.out.println(num);

}

}

当然,也可以使用线程保险的包装器Collections.synchronizedList来创建一个同步的ArrayList:

List synchronizedList = Collections.synchronizedList(new ArrayList<>());

synchronizedList.add(1);

synchronizedList.add(2);

synchronizedList.add(3);

for (Integer num : synchronizedList) {

System.out.println(num);

}

九、总结

ArrayList是Java中常用的数据结构之一,掌握其源码分析对于深入明白Java集合框架非常重要。本文详细介绍了ArrayList的核心成员变量、构造方法、扩容机制、添加和删除元素方法、遍历方法以及线程保险性,期待对读者有所帮助。


本文由IT视界版权所有,禁止未经同意的情况下转发

文章标签: 后端开发


热门