一、ArrayList的定义:
public class ArrayList<E>
extends AbstractList<E>
implements List<E>, RandomAccess, Cloneable, java.io.Serializable
从上述定义可以看出:
1. ArrayList继承自AbstractList,实现了List,所以它是一个队列,支持相关的添加、删除、修改、遍历等功能。
2. ArrayList实现了RandomAccess接口,即提供了随机访问功能。RandmoAccess是java中用来被List实现,为List提供快速访问功能的。
3. ArrayList实现了Cloneable接口,即实现clone()函数。它能被克隆。
4. ArrayList实现了java.io.Serializable接口,支持序列化。
5. ArrayList是支持泛型的。
二、ArrayList的基本属性:
ArrayList只定义了两个基本属性:存放元素的数组和数组大小。
/**
* The array buffer into which the elements of the ArrayList are stored.
* The capacity of the ArrayList is the length of this array buffer.
*/
private transient Object[] elementData;
/**
* The size of the ArrayList (the number of elements it contains).
*
* @serial
*/
private int size;
三、ArrayList的构造方法:
1. 第一个构造方法(不带参数):
/**
* Constructs an empty list with an initial capacity of ten.
*/
public ArrayList() {
this(10);
}
2. 第二个构造方法(带一个参数:初始容量):
/**
* Constructs an empty list with the specified initial capacity.
*/
public ArrayList(int initialCapacity) {
super();
if (initialCapacity < 0)
throw new IllegalArgumentException("Illegal Capacity: "+
initialCapacity);
this.elementData = new Object[initialCapacity];
}
3. 第三个构造方法(传入一个集合)
/**
* Constructs a list containing the elements of the specified
* collection, in the order they are returned by the collection's
* iterator.
*/
public ArrayList(Collection<? extends E> c) {
elementData = c.toArray();
size = elementData.length;
// c.toArray might (incorrectly) not return Object[] (see 6260652)
if (elementData.getClass() != Object[].class)
elementData = Arrays.copyOf(elementData, size, Object[].class);
}
四、ArrayList增加元素方法:
1. add(E e):在数组末尾增加一个元素。
public boolean add(E e) {
ensureCapacity(size + 1); // Increments modCount!!
elementData[size++] = e;
return true;
}
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);
}
}
增加modCount之后,判断minCapacity(即size+1)是否大于oldCapacity(即elementData.length),若大于,则调整容量为max((oldCapacity*3)/2+1,minCapacity),调整elementData容量为新的容量,即将返回一个内容为原数组元素,大小为新容量的数组赋给elementData;否则不做操作。
因此可以看出:
ArrayList容量的拓展将导致数组元素的复制,多次拓展容量将执行多次整个数组内容的复制。若提前能大致判断list的长度,调用ensureCapacity调整容量,将有效的提高运行速度。
另外,ArrayList每次容量扩展大概是原来的1.5倍,增长二分之一。
2. add(int index, E element):在指定索引处添加元素。
public void add(int index, E element) {
if (index > size || index < 0)
throw new IndexOutOfBoundsException(
"Index: "+index+", Size: "+size);
ensureCapacity(size+1); // Increments modCount!!
System.arraycopy(elementData, index, elementData, index + 1,
size - index);
elementData[index] = element;
size++;
}
首先判断指定位置index是否超出elementData的界限,之后调用ensureCapacity调整容量(若容量足够则不会拓展),调用System.arraycopy将elementData从index开始的size-index个元素复制到index+1至size+1的位置(即index开始的元素都向后移动一个位置),然后将index位置的值指向element。
3. addAll(Collection<? extends E> c):将一个arrayList添加到另一个arrayList中。
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;
}
先将集合c转换成数组,根据转换后数组的程度和ArrayList的size拓展容量,之后调用System.arraycopy方法复制元素到elementData的尾部,调整size。根据返回的内容分析,只要集合c的大小不为空,即转换后的数组长度不为0则返回true。
4. addAll(int index,Collection<? extends E> c):将一个arrayList添加到另一个arrayList的指定索引处。
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);
System.arraycopy(a, 0, elementData, index, numNew);
size += numNew;
return numNew != 0;
}
先判断index是否越界。其他内容与addAll(Collection<? extends E> c)基本一致,只是复制的时候先将index开始的元素向后移动X(c转为数组后的长度)个位置(也是一个复制的过程),之后将数组内容复制到elementData的index位置至index+X。
五、ArrayList的删除元素方法:
1. remove(int index)方法:移除指定位置的元素。
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);
elementData[--size] = null; // Let gc do its work
return oldValue;
}
首先是检查范围,修改modCount,保留将要被移除的元素,将移除位置之后的元素向前挪动一个位置,将list末尾元素置空(null),返回被移除的元素。
2. remove(Object o)方法:移除指定元素的元素。
public boolean remove(Object o) {
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;
}
首先通过代码可以看到,当移除成功后返回true,否则返回false。remove(Object o)中通过遍历element寻找是否存在传入对象,一旦找到就调用fastRemove移除对象。为什么找到了元素就知道了index,不通过remove(index)来移除元素呢?因为fastRemove跳过了判断边界的处理,因为找到元素就相当于确定了index不会超过边界,而且fastRemove并不返回被移除的元素。下面是fastRemove的代码,基本和remove(index)一致。
fastRemove():
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
}
3. removeRange(int fromIndex,int toIndex):移除指定范围的元素。
protected void removeRange(int fromIndex, int toIndex) {
modCount++;
int numMoved = size - toIndex;
System.arraycopy(elementData, toIndex, elementData, fromIndex,
numMoved);
// Let gc do its work
int newSize = size - (toIndex-fromIndex);
while (size != newSize)
elementData[--size] = null;
}
执行过程是将elementData从toIndex位置开始的元素向前移动到fromIndex,然后将toIndex位置之后的元素全部置空顺便修改size。
4. clear():清空ArrayList方法。
public void clear() {
modCount++;
// Let gc do its work
for (int i = 0; i < size; i++)
elementData[i] = null;
size = 0;
}
clear的时候并没有修改elementData的长度(好不容易申请、拓展来的,凭什么释放,留着搞不好还有用呢。这使得确定不再修改list内容之后最好调用trimToSize来释放掉一些空间),只是将所有元素置为null,size设置为0。即clear方法只是将数组里的元素置为null,ArrayList的大小置为0,并没有释放内存。
六、ArrayList的修改元素方法:
1. set(int index,E element): 修改指定索引位置的元素的值。
public E set(int index, E element) {
RangeCheck(index);
E oldValue = (E) elementData[index];
elementData[index] = element;
return oldValue;
}
首先检查范围,用新元素替换旧元素并返回旧元素。
七、ArrayList的获取元素方法:
1. get(int index):获取指定索引的元素。
public E get(int index) {
RangeCheck(index);
return (E) elementData[index];
}
先调用RangeCheck方法检测索引是否越界,然后直接根据数组下标获取数组元素,由此可以看出ArrayList是元素插入慢,但是查询快(数组的查询速度是很快的)。
八、ArrayList的索引相关方法:
1. indexOf(Object):获取元素在ArrayList中索引。
public int indexOf(Object o) {
if (o == null) {
for (int i = 0; i < size; i++)
if (elementData[i]==null)
return i;
} else {
for (int i = 0; i < size; i++)
if (o.equals(elementData[i]))
return i;
}
return -1;
}
通过遍历elementData数组来判断对象是否在list中,若存在,返回元素的index([0,size-1]),若不存在则返回-1。
2. lastIndexOf():获取指定元素最后出现的索引值。
public int lastIndexOf(Object o) {
if (o == null) {
for (int i = size-1; i >= 0; i--)
if (elementData[i]==null)
return i;
} else {
for (int i = size-1; i >= 0; i--)
if (o.equals(elementData[i]))
return i;
}
return -1;
}
采用了从后向前遍历element数组,若遇到Object则返回index值,若没有遇到,返回-1。
九、ArrayList的其他方法:
1. isEmpty():判断ArrayList是否为空。
public boolean isEmpty() {
return size == 0;
}
直接返回size是否等于0。
2. size():获取ArrayList的大小。
public int size() {
return size;
}
3. contains(Object):判断元素是否在ArrayList中。
public boolean contains(Object o) {
return indexOf(o) >= 0;
}
4. toArray():将ArrayList转换成数组。
public Object[] toArray() {
return Arrays.copyOf(elementData, size);
}
调用Arrays.copyOf将返回一个数组,数组内容是size个elementData的元素,即拷贝elementData从0至size-1位置的元素到新数组并返回。
以下是泛型方式写法:
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;
}
如果传入数组的长度小于size,返回一个新的数组,大小为size,类型与传入数组相同。所传入数组长度与size相等,则将elementData复制到传入数组中并返回传入的数组。若传入数组长度大于size,除了复制elementData外,还将把返回数组的第size个元素置为空。
5. trimToSize():压缩存放元素数组的空间大小。
public void trimToSize() {
modCount++;
int oldCapacity = elementData.length;
if (size < oldCapacity) {
elementData = Arrays.copyOf(elementData, size);
}
}
由于elementData的长度会被拓展,size标记的是其中包含的元素的个数。所以会出现size很小但elementData.length很大的情况,将出现空间的浪费。trimToSize将返回一个新的数组给elementData,元素内容保持不变,length很size相同,节省空间。
十、ArrayList与LinkList的比较:
1. 实现方式:ArrayList是实现了基于动态数组的数据结构,LinkedList基于链表的数据结构。
2. 随机访问速度:因为ArrayList底层由数组实现,LinkedList是双向链表,所以ArrayList的随机访问速度要比LinkedList快。
3. 插入删除速度:因为ArrayList底层由数组实现,在0号位置插入时将移动list的所有元素,在末尾插入元素时不需要移动。LinkedList是双向链表,在任意位置插入元素所需时间均相同。所以LinkedList插入删除速度要比ArrayList快。
综上所述,在List中有较多插入和删除操作的情况下应使用LinkedList来提高效率,而有较多索引查询的时候使用ArrayList(使用增强型的for循环或Iterator遍历LinkedList效率将提高很多)。
相关推荐
7. **集合框架**:JDK 1.6的`java.util`包包含了各种集合实现,如ArrayList、LinkedList、HashMap等。源码分析可以揭示它们的内部结构和操作算法,这对于理解性能和选择合适的集合类型很有帮助。 8. **网络编程**:...
**JDK1.6 API中文版** Java Development Kit (JDK) 1.6是Java编程语言的一个重要版本,它包含了一系列的开发工具和Java运行环境。API(Application Programming Interface)是JDK的核心部分,提供了丰富的类库供...
Java开发工具JDK1.6源码的获取与分析对于深入理解Java语言的内部机制、优化编程技巧以及排查问题有着至关重要的作用。源码能够揭示出API背后的实现细节,帮助开发者提升技能,增强代码质量。以下将详细介绍如何在...
**JDK 1.6 源码详解** JDK(Java Development Kit)1.6,也被称为Java SE 6,是Oracle公司发布的Java平台标准版的一个重要版本。这个版本的发布为Java开发者提供了大量的新特性和改进,使得Java编程更加高效、安全...
**Java Development Kit (JDK) 1.6 源码包详解** JDK 1.6源码包是Java编程语言的核心开发工具集,它包含了大量的类库和工具,为开发者提供了深入理解Java平台工作原理的机会。源码包允许程序员查看并研究Java API的...
2. **集合框架**:JDK1.6进一步完善了集合框架,包括List、Set、Map等接口及其实现类,如ArrayList、LinkedList、HashSet、HashMap等。这些类提供了丰富的操作方法,使得数据组织和管理更为便捷。 3. **IO流**:JDK...
JDK1.6的集合框架是Java开发中的重要组成部分,包括List、Set、Map等接口以及ArrayList、LinkedList、HashSet、HashMap等实现类。这些集合类提供了丰富的数据存储和操作功能,例如添加、删除、查找元素,以及对集合...
2. **集合框架**:JDK1.6中的集合框架是Java编程中的重要组成部分,包括ArrayList、LinkedList、HashSet、HashMap等数据结构。这些集合类提供了丰富的操作方法,帮助开发者高效地存储和处理数据。 3. **网络编程**...
JDK 1.6中文API是Java开发的重要参考资料,它包含了Java 1.6版本的所有公共类、接口、枚举、异常以及它们的方法和属性,为开发者提供了详尽的解释和示例。本文将围绕JDK 1.6中文API,深入探讨其中的关键知识点,帮助...
**JDK1.6源代码详解** JDK(Java Development Kit)是Oracle公司提供的Java编程环境,包含了编译器、运行时环境、调试工具和其他实用工具。JDK1.6,也被称为Java SE 6,是Java历史上的一个重要版本,发布于2006年,...
在JDK 1.6中,ArrayList提供了线程不安全的高效操作,适合于非并发环境下的高性能读写操作。其优点在于随机访问快速,因为数组支持索引直接访问;缺点是插入和删除元素需要移动后续元素,效率较低。 Vector与...
- **泛型的类型推断(Type Inference for Generic Instance Creation)**:JDK 1.6引入了类型推断,使得使用匿名内部类创建泛型实例时更简洁,如`List<String> list = new ArrayList()`。 - **枚举类型实例的比较...
《JDK1.6 API中文文档HTML版》是Java开发者的重要参考资料,它包含了JDK1.6版本的所有公共类和接口的详细说明。这个文档以HTML格式呈现,方便用户在线浏览或离线阅读,尤其对于中文环境下的开发者,中文版API文档能...
**JDK 1.6 带索引 API 知识点详解** JDK 1.6,也称为 Java Development Kit 1.6 或 Java SE 6,是Oracle公司发布的一个重要的Java平台版本,它在Java 1.5的基础上进行了一系列的改进和增强。这个版本的API带索引...
在本案例中,我们讨论的是JDK 1.6版本,这是一个较早但仍然在许多系统中使用的版本。 **Java环境配置**是使用Java技术的第一步。在Windows操作系统中,配置通常包括设置`JAVA_HOME`环境变量指向JDK的安装目录,然后...
**JDK 1.6 帮助文档中文版** JDK(Java Development Kit)是Oracle公司提供的用于开发和运行Java应用程序的工具集合。版本1.6,也被称为Java SE 6,是Java平台标准版的一个重要里程碑。这个版本包含了Java编译器、...
Java JDK1.6学习笔记是一份详实的资料,涵盖了Java开发工具集(JDK)1.6版本的核心概念和技术。这份笔记对于Java初学者以及有一定经验的开发者来说都是一份宝贵的参考资料,它可能包含了从基础语法到高级特性的讲解...
12. **集合框架**:JDK1.6中的集合框架是`java.util`包的一大亮点,包括List、Set、Map接口,以及ArrayList、LinkedList、HashSet、HashMap等实现类。 13. **注解(Annotation)**:JDK1.6引入了注解,这是一种元...
**二、JDK 1.6新特性** 1. **增强的枚举(enum)**:在JDK 1.5引入枚举类型后,1.6版本进一步增强了枚举的使用,包括枚举常量之间的比较和遍历。 2. **泛型(Generics)**:泛型增加了类型安全,允许在编译时检查...
**JDK1.6 API帮助文档详解** JDK1.6 API(Application Programming Interface)是Java开发者的重要参考资料,它包含了Java开发工具包的所有类库、接口和方法的详细描述,为程序员提供了丰富的功能调用和编程指导。...