list内部实现是一个名叫elementData的数组
1>list类的构造函数:
private transient Object[] elementData;//用来作为一个缓冲数组
//带初始化的构造函数,initialCapacity代表数组的初始容量
public ArrayList(int initialCapacity) {
super();
if (initialCapacity < 0)
throw new IllegalArgumentException("Illegal Capacity: "+
initialCapacity);
//根据用户传进initialCapacity初始化一个数组
this.elementData = new Object[initialCapacity];
}
/**
* Constructs an empty list with an initial capacity of ten.
*/
//如果用户调用了不带参数的构造函数,系统默认初始化大小为10
public ArrayList() {
this(10);
}
//还有一个全局size,时刻记录着元素的个数,代表着list的实际容量
private int size;
2>add(): 向列表的尾部添加指定的元素(可选操作)
public boolean add(E e) {
//ensureCapacity用来检查如果数组中插入了这个值容量是否溢出,
ensureCapacity(size + 1); // Increments modCount!!
//在当前的位置插入元素,并把size+1;
elementData[size++] = e;
return true;
}
//注意这个检查边界的函数,后面的方法中差不多都会用到
public void ensureCapacity(int minCapacity) {
modCount++;
int oldCapacity = elementData.length;//xian把原来数组的长度存起来
if (minCapacity > oldCapacity) {//如果添加了元素之后,数组溢出,
Object oldData[] = elementData;//将原来数组的值存到另一个数组中
int newCapacity = (oldCapacity * 3)/2 + 1;//新开辟的空间在原来的基础上扩大1.5倍+1
if (newCapacity < minCapacity)//如果新的容量还不能足够的容纳要添加的元素个数
newCapacity = minCapacity;//就把新容量定为要添加的元素个数
// minCapacity is usually close to size, so this is a win:
//将elementData扩容后的数组返回给他自己,其中的内容不变,只是容量变大
//Arrays.copyOf函数做了好多事,最总调用的还是System.ArrayCopy(...)
elementData = Arrays.copyOf(elementData, newCapacity);
}
}
3>add(int index, E element):制定的位置插入元素
/**
*
* @param index 要插入的位置
* @param 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!!
/*
* @param elementData 将要被拷贝的元素
* @param index 从那个位置开始拷贝
* @param elementData 拷贝到哪里去(目标数组)
* @param index + 1 拷贝到目标数组的那个位置
* @param size - index 拷贝多少个元素
* 这个方法的作用 把用户指定的位置的元素,一次向后移动一个单位
* 例如:
* elementData[1,2,4,5]现在要在下标为2的位置插入3
* 这句这句话执行完的效果是是
* elementData[1,2,4,4,5] 可以看到45依次向后移动一个位置,新进来的元素直接覆盖2后面的4
* 最终: elementData[1,2,3,4,5]
*
*/
System.arraycopy(elementData, index, elementData, index + 1,
size - index);
elementData[index] = element;//这句话就是覆盖
size++;//元素个数+1
}
4>addAll(int index, Collection
/**
*
* @param c 要添加的集合
* @return
*/
public boolean addAll(Collection extends E> c) {
Object[] a = c.toArray();//把集合转换成数组,先存起来
int numNew = a.length;//numNew存的是集合的元素个数
//检查元素插入这些集合元素后是否溢出,溢出扩容
ensureCapacity(size + numNew); // Increments modCount
//把 a数组元素从0开始的位置长度为numNew个元素复制到elementData中size个位置,也就是默认追加到原来的元素之后
//list还有一个方法可以指定吧c集合添加到那个位置上,仅仅是把这里的size值改变为用户指定的值即可
System.arraycopy(a, 0, elementData, size, numNew);
size += numNew;
return numNew != 0;
}
5>clear():从列表中移除所有元素
//很简单,遍历数组把元素清空就行,不要忘记了把size置0
public void clear() {
modCount++;
// Let gc do its work
for (int i = 0; i < size; i++)
elementData[i] = null;
size = 0;
}
6>contains(Object o):如果列表包含指定的元素,则返回 true
/**
* 代码也很简单,只是要记得判断null
* @param o 要判断的元素
* @return
*/
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;
}
}
7>equals(Object o) :比较指定的对象与列表是否相等
/**
* @param Object o 要比较的内容
*/
public boolean equals(Object o) {
//如果要比交的是自己本身直接返回true,感慨大师写的代码是有多么的严谨呀
if (o == this)
return true;
//如果要计较的对象不是list那还比较啥,直接返回false
if (!(o instanceof List))
return false;
//分别遍历集合挨个比较,只要有一个不想等直接返回false
ListIterator e1 = listIterator();
ListIterator e2 = ((List) o).listIterator();
while(e1.hasNext() && e2.hasNext()) {
E o1 = e1.next();
Object o2 = e2.next();
//如果o1 == null o2 == null 这个表达式为true, 则整个if条件为false,继续while比较下一个
//如果o1!= null 执行o1.equals(o2) 为真,则if条件为假,继续执行while
if (!(o1==null ? o2==null : o1.equals(o2)))
return false;
}
//当对象o1 或者对象o2任意一个遍历到尾部时跳出while循环,这是只能说明o1可能包含着o2
//比如说o1[1,2,3,4,5] o2[1,2,3,4],这样的例子是完全符合的,只有o1和o2的元素完全相等,并且长度也相等时才算真的相等
//那么下面的这句就是用来比较长度是否相等的,我感觉是否可以先判断长度,在判断元素是否相等,这样是否更有效的
//一己之见,可能本人眼拙 还未达到大师的水平
return !(e1.hasNext() || e2.hasNext());
}
8> E get(int index) :返回列表中指定位置的元素
比较简单
/**
*
* @param index 要查找的元素下表
* @return
*/
public E get(int index) {
//检查范围
RangeCheck(index);
return (E) elementData[index];
}
/**
*
* @param index
*/
private void RangeCheck(int index) {
if (index >= size)
throw new IndexOutOfBoundsException(
"Index: "+index+", Size: "+size);
}
9>hashCode():返回列表的哈希码值
原来hashcode是这样产生的
public int hashCode() {
int hashCode = 1;
Iterator i = iterator();
while (i.hasNext()) {
E obj = i.next();
hashCode = 31*hashCode + (obj==null ? 0 : obj.hashCode());
}
return hashCode;
}
10>indexOf(Object o):回此列表中第一次出现的指定元素的索引;如果此列表不包含该元素,则返回 -1。
参考前面的equals()方法
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;
}
11>isEmpty() : 如果列表不包含元素,则返回 true
好简单,但是如果让我们自己设计时,我们该怎样设计呢
public boolean isEmpty() {
return size == 0;
}
12>lastIndexOf(Object o)
和indexOf()差不多,只是从头开始
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;
}
13>remove(int index): 移除列表中指定位置的元素
检查index值是否非法,size-1 删除的元素之后的元素一次向前移动
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;
}
还有方法都差不多,这里不再分析