ArrayList的内部实现是Object数组,当插入对象时会检查数组长度是否够,不够会创建个更大的数组并拷贝原来数组的所有元素。检索速度快;插入、删除速度慢:被插入或删除的元素离ArrayList尾部越远,耗费的性能会越大(因为移动的子数组越大)。
size()和数组的长度是不同的:
size是指有效元素的个数,小于或等于数组的长度。
1. toArray方法
将ArrayList实例中的所有元素拷贝到一个数组中
如果目标数组的长度小于ArrayList的长度,则根据数组的类型生成一个新的数组并拷贝;
否则就调用System.arraycopy方法复制数据,如果目标数组的长度大于ArrayList的长度,数组中在list后面的第一个位置被赋为null。
public <T> T[] toArray(T[] a) {
if (a.length < size)
// Make a new array of a's runtime type, but my contents:
return (T[]) Arrays.copyOf(elementData, size, a.getClass());
System.arraycopy(elementData, 0, a, 0, size);
if (a.length > size)
a[size] = null;
return a;
}
测试代码:
ArrayList list = new ArrayList();
list.add("Disable");
list.add("the");
list.add("current");
list.add("thread");
String[] array = new String[3];
//String[] array = new String[4];
//String[] array = new String[6];
String[] arrayCopy = (String[])list.toArray(array);
// when 3: false
// when 4, 6: true
System.out.println(arrayCopy == array);
// when 3, 4: ["Disable", "the", "current", "thread"]
// when 6: ["Disable", "the", "current", "thread", null, null]
System.out.println(Arrays.toString(arrayCopy));
2. trimToSize方法
// 和ensureCapacity相对应,去除空余的位置,节省存储空间
public void trimToSize() {
modCount++;
int oldCapacity = elementData.length;
if (size < oldCapacity) {
elementData = Arrays.copyOf(elementData, size);
}
}
3. ensureCapacity方法
// 通过新建更大的数组并拷贝原来的元素来实现扩容。
public void ensureCapacity(int minCapacity) {
modCount++;
int oldCapacity = elementData.length;
if (minCapacity > oldCapacity) {
Object oldData[] = elementData;
int newCapacity = (oldCapacity * 3)/2 + 1; // 增长因子
if (newCapacity < minCapacity) // 如果长度还不够,使用参数大小
newCapacity = minCapacity;
// minCapacity is usually close to size, so this is a win:
elementData = Arrays.copyOf(elementData, newCapacity); // 新建数组并拷贝原来的所有元素到新数组上
}
}
4. clone方法
public Object clone() {
try {
ArrayList<E> v = (ArrayList<E>) super.clone();
v.elementData = Arrays.copyOf(elementData, size);
v.modCount = 0;
return v;
} catch (CloneNotSupportedException e) {
// this shouldn't happen, since we are Cloneable
throw new InternalError();
}
}
测试clone方法:
private static class Representative {
String name;
public Representative(String name) {
this.name = name;
}
// Getter and setters are omitted
}
private static void testClone() {
ArrayList<Representative> list = new ArrayList<Representative>();
Representative representative = new Representative("Hence");
list.add(representative);
ArrayList<Representative> listClone = (ArrayList<Representative>) list.clone();
System.out.println(list.get(0) == listClone.get(0));
representative.setName("whenever");
System.out.println(listClone.get(0).name); // whenever
}
可以看出,clone方法实现了浅度复制。
5. get和set方法
public E set(int index, E element) {
RangeCheck(index);
E oldValue = (E) elementData[index];
elementData[index] = element;
return oldValue;
}
public E get(int index) {
RangeCheck(index);
return (E) elementData[index];
}
get和set都会首先检查index有没越界,set返回的是被替换的数据。
6. add方法
public boolean add(E e) {
ensureCapacity(size + 1); // Increments modCount!!
elementData[size++] = e;
return true;
}
public void add(int index, E element) {
if (index > size || index < 0)
throw new IndexOutOfBoundsException(
"Index: "+index+", Size: "+size);
// 首先确保检查数组大小足够
ensureCapacity(size+1); // Increments modCount!!
// 把index和以后的元素都后移一位,性能会大幅下降
System.arraycopy(elementData, index, elementData, index + 1,
size - index);
// index位置存储指定对象的引用
elementData[index] = element;
size++;
}
addAll方法
public boolean addAll(Collection<? extends E> c) {
Object[] a = c.toArray(); // 集合对象转换成数组
int numNew = a.length;
ensureCapacity(size + numNew); // Increments modCount
System.arraycopy(a, 0, elementData, size, numNew); // 追加到尾部
size += numNew;
return numNew != 0;
}
public boolean addAll(int index, Collection<? extends E> c) {
if (index > size || index < 0)
throw new IndexOutOfBoundsException(
"Index: " + index + ", Size: " + size);
Object[] a = c.toArray(); // 集合对象转换为数组
int numNew = a.length;
ensureCapacity(size + numNew); // Increments modCount
int numMoved = size - index; // 后移的元素的个数
if (numMoved > 0)
System.arraycopy(elementData, index, elementData, index + numNew,
numMoved); // index+numNew为后移的幅度
System.arraycopy(a, 0, elementData, index, numNew); // 拷贝需要添加的数组到index位置
size += numNew;
return numNew != 0;
}
7. remove方法
public E remove(int index) {
RangeCheck(index);
modCount++;
E oldValue = (E) elementData[index]; // 暂存被删除元素
int numMoved = size - index - 1; // 需要移动的元素的个数
if (numMoved > 0)
System.arraycopy(elementData, index+1, elementData, index,
numMoved); // index+1和之后的元素前移一位
elementData[--size] = null; // Let gc do its work
return oldValue;
}
// List是有序且可以有重复元素的,该方法会删除符合的第一个元素
public boolean remove(Object o) {
// 优化:对null元素单独进行处理
if (o == null) {
for (int index = 0; index < size; index++)
if (elementData[index] == null) {
fastRemove(index);
return true;
}
} else {
for (int index = 0; index < size; index++)
if (o.equals(elementData[index])) {
fastRemove(index);
return true;
}
}
return false;
}
// 和remove(int index)类似,不同的是少了越界检测和返回被删除的元素
private void fastRemove(int index) {
modCount++;
int numMoved = size - index - 1;
if (numMoved > 0)
System.arraycopy(elementData, index+1, elementData, index,
numMoved);
elementData[--size] = null; // Let gc do its work
}
// 删除从fromIndex到toIndex(不包括)之间的元素
protected void removeRange(int fromIndex, int toIndex) {
modCount++;
int numMoved = size - toIndex; // 需要移动的元素个数
System.arraycopy(elementData, toIndex, elementData, fromIndex,
numMoved); // toIndex和以后的元素移到fromIndex位置
// Let gc do its work
int newSize = size - (toIndex-fromIndex); // 新的大小
while (size != newSize) // 后面的几个位置清空
elementData[--size] = null;
}
测试remove方法:
private static void testRemoveNull() {
ArrayList<String> list = new ArrayList<String>();
list.add(null);
list.add("queen");
list.add(null);
list.add(null);
System.out.println(list); // [null, queen, null, null]
list.remove(null);
System.out.println(list); // [queen, null, null]
}
8. readObject和writeObject方法
private void writeObject(java.io.ObjectOutputStream s)
throws java.io.IOException{
// Write out element count, and any hidden stuff
int expectedModCount = modCount;
s.defaultWriteObject();
// Write out array length
s.writeInt(elementData.length);
// Write out all elements in the proper order.
for (int i=0; i<size; i++)
s.writeObject(elementData[i]);
if (modCount != expectedModCount) {
throw new ConcurrentModificationException();
}
}
private void readObject(java.io.ObjectInputStream s)
throws java.io.IOException, ClassNotFoundException {
// Read in size, and any hidden stuff
s.defaultReadObject();
// Read in array length and allocate array
int arrayLength = s.readInt();
Object[] a = elementData = new Object[arrayLength];
// Read in all elements in the proper order.
for (int i=0; i<size; i++)
a[i] = s.readObject();
}
分享到:
相关推荐
根据arraylist源码分析,自己编写了一个类似于arraylist集合的代码
ArrayList的源码,写了一些自己的分析,包括jdk1.8的新特性
ArrayList源码分析_016.pdf
来自视频课笔记 面试肯定没问题 包含线程安全的list和不安全的list
一 前言 知识追寻者目前的系列都是基于jdk1.8进行学习分析;...二 ArrayList源码分析 2.2 空参构造方法源码分析 调试代码 public static void main(String[] args) { // 初始化长度为0 ArrayList list =
主要介绍了Java编程中ArrayList源码分析,具有一定借鉴价值,需要的朋友可以参考下。
主要为大家详细介绍了Java集合框架ArrayList源码分析,感兴趣的小伙伴们可以参考一下
ArrayList 源码深度解析 一、重新认识ArrayList 什么是ArrayList? ArrayList是基于数组实现的List类,封装了一个动态再分配的Object数组,以达到可以动态增长和缩减的索引序列。 长啥样? 如图,是一个长度为6,...
基于jdk1.8 的ArrayList的源码分析 前言:一说到ArrayList的大家可能立马想到的就是:有序、可重复、查找快但是增删慢、线程不安全。但是具体的原因都不是很清楚,本文就会根据这些问题和大家一起去学习。主要会从...
主要为大家详细介绍了Java集合系列之ArrayList源码,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
史上最全ArrayList源码分析
源码分析见我博文:http://blog.csdn.net/wabiaozia/article/details/50684556
计算机后端-Java-Java核心基础-第24章 集合01 14. ArrayList的源码分析.avi
本资源根据个人学习和总结,主要介绍Java中ArrayList扩容机制源码的解析,主要包含文字和代码等内容,以源码的形式进行分析,详细介绍了ArrayList扩容机制的整个流程,特此将该资源分享
能学到什么:ArrayList的源码分析,自动扩容和自动缩容的源码分析,相关参数的深度解析,从是什么,为什么,怎么做三个角度进行讲解,用通俗易懂的白话进行介绍,LinkedList和Vector以及ArrayList的区别以及使用场景...
ArrayList源码分析(基于JDK8) 因为Vector和ArrayList除了数组扩容有点差别,还有加锁使Vector迈进了线程安全的行列外,底层实现大约是没有太大区别的!基本一致!线程安全问题更是另当别论了!继续往下看就OK! ...