一、集合
java中集合有两个接口:Collection和Map。
Collection是一个集合接口。提供了对集合对象的基本操作和通用方法。
Collections则是一个工具类。
继承Collection接口的常用的集合Set和List接口。它们都是用来存储一组相同类型元素的数据。
Set:元素无序,不重复。
List:元素有序,可重复。
二、List接口
List接口的实现主要有ArrayList、LinkedList与Vector。
- ArrayList:ArrayList是一个可改变大小的集合。其大小可以动态增长的,增长的大小为百分之五十。内部元素可以使用get和set方式进行访问。
- LinkedList:LinkedList是一个可改变大小的集合。其大小也是动态增长的。是一个链表结构的集合。主要是删除和添加元素的性能要高于ArrayList,但是访问内部元素的性能比ArrayList低。
- Vector:Vector也是一个可改变大小的集合。其大小可以动态增长,但是增长的大小为百分之百。并且Vector是线程安全的。ArrayList不是。
三、ArrayList源码
3.1 ArrayList类的继承关系
ArrayList类的继承关系如下图所示:
ArrayList主要是实现了Cloneable、Serializable、RandomAccess接口以及实现了AbstractList类。
- Cloneable:这是一个标记型接口。实现了该接口则表示这类可以被clone。
- Serializable:这个也是一个标记型的接口。实现该接口则表示这个类可以被序列化。
- RandomAccess:这个是一个标记型接口。实现了该接口则表示这个类支持快速访问。
- AbstractList:这个是实现了List接口的抽象类,AbstractList中实现了一些List的基本实现。
3.2 ArrayList中的属性
ArrayList中的主要属性如下:
- DEFAULT_CAPACITY:默认的初始化ArrayList大小。
- elementData:ArraryList中存储的数组缓存。
- EMPTY_ELEMENTDATA:用于创建实例的时候将这个空的数组复制给elementData。
- DEFAULTCAPACITY_EMPTY_ELEMENTDATA:用于创建实例的时候将这个空的数组复制给elementData,和EMPTY_ELEMENTDATA区别就是在于这个是无参构造函数时候赋值。
- size:当前ArrayList的大小(java 成员变量int型,默认值是0)。
3.3 构造方法
ArrayList的主要的构造方法有下面几个:
- 无参构造方法:无参构造方法主要是将 默认的空的元素数组赋值给了变量elementData。
public ArrayList() {
this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}
- 参数为int的构造方法:构造方法参数为int,int是指定初始化elementData数组的大小。
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);
}
}
- 参数为集合的构造方法:构造方法的参数为Collection的集合。
public ArrayList(Collection<? extends E> c) {
elementData = c.toArray();
if ((size = elementData.length) != 0) {
// c.toArray might (incorrectly) not return Object[] (see 6260652)
if (elementData.getClass() != Object[].class)
elementData = Arrays.copyOf(elementData, size, Object[].class);
} else {
// replace with empty array.
this.elementData = EMPTY_ELEMENTDATA;
}
}
3.4 ArrayList的常用方法
3.4.1 ensureCapacity
ensureCapacity是确定当前容纳的元素的数量是不是大于指定最小的容量。
public void ensureCapacity(int minCapacity) {
int minExpand = (elementData != DEFAULTCAPACITY_EMPTY_ELEMENTDATA)
// any size if not default element table
? 0
// larger than default for default empty table. It's already
// supposed to be at default size.
: DEFAULT_CAPACITY;
if (minCapacity > minExpand) {
ensureExplicitCapacity(minCapacity);
}
}
判断当前的的的数组是不是初始化的DEFAULTCAPACITY_EMPTY_ELEMENTDATA,是则返回0,不是返回默认大小。然后判断指定的最小容量是否大于minExpand。假设当前的数组的长度小于需要扩展的容量大小,则会变成数组elementData的数组长度。
3.4.2 grow
grow是对ArrayList里面数组容量的扩展,此方法是私有化的,仅在ArrayList里面使用。
private void grow(int minCapacity) {
// overflow-conscious code
int oldCapacity = elementData.length;
int newCapacity = oldCapacity + (oldCapacity >> 1);
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);
}
核心就是在新的长度是老的长度加上老的长度的右移一位(即老的长度的1.5倍),判断新的长度是否大于指定的容量,假设大于则使用新计算的长度为elementData数组的长度,反之则使用指定长度为elementData的长度。
3.4.3 contains/indexOf
contains/indexOf的参数都是一个指定的对象,主要的作用就是判断当前的对象是不是在这个元素elementData数组中。
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;
}
3.4.4 toArray
toArray是将当前的的list转换成泛型数组。方法参数是一个泛型的数组。
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;
}
3.4.5 get
get是返回elementData指定下表的元素。方法参数是一个int型的下标。返回一个泛型。
public E get(int index) {
rangeCheck(index);
return elementData(index);
}
判断指定下标是否超过了当前的list的大小,超过则抛出异常。
3.4.6 add
add是添加一个指定的泛型的元素到数组elementData中。
public boolean add(E e) {
ensureCapacityInternal(size + 1); // Increments modCount!!
elementData[size++] = e;
return true;
}
3.4.7 remove
remove是删除第一个匹配的元素。方法参数是一个指定的对象。
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;
}
remove方法是就是遍历elementData数组,和指定对象做比较,若两个对象一样,记录当前的下标,计算出需要移动的长度,将当前对象的下标+1到当前elements最后一个元素全部往前挪一位。
3.4.8 iterator
iterator方法就是返回一个迭代器。利用迭代器操作elements数组。