ArrayList是list集合的实现接口,在我们日常生活中使用频率非常大,而且他随着元素的添加而自动扩增容量,而使得他不被撑爆,那么他是如何实现这一神奇的地方的呢,借此,凭着打破砂锅问到底的原则,打开源码进行一探究竟,看看是何方神圣。当我们点击ArrayList时,可以看到他的构造方法
private transient Object[] elementData;//这个是ArrayList类中object数组变量。
public ArrayList(int initialCapacity) {
super();
if (initialCapacity < 0)
throw new IllegalArgumentException("Illegal Capacity: "+
initialCapacity);
this.elementData = new Object[initialCapacity];
}
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);
}
public ArrayList() {
this(10);
}
首先,我第一眼看到这个这个构造函数是,我就明白了,原来ArrayList就是一个数组的存储过程,并且初始化的时候就默认给了一个大小为10的容量。并且把这个集合中的元素存到object的数组中。elementData.getClass() != Object[].class当这个条件满足时说明有新的元素进来,那就Arrays.copyOf(elementData, size, Object[].class);通过数组静态工具进行将改添加进来的元素copy到object的数组中去,这样就可以得到实时更新数据.那么我们现在来看看这个集合中的添加操作
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);
}
}
在这个方法中实现了对数组的扩充。增加容量。并且在这个方法中用到了一个算法。int newCapacity = (oldCapacity * 3)/2 + 1;这个方法可以至少扩至一个容量。然后对这个算出来的值再进一步判断,最后将对比的值赋值给他,这样做的目的是防止越界操作,然后调用数组的静态方法进行扩容操作.我们再回到这个添加方法中来。
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!!
System.arraycopy(elementData, index, elementData, index + 1,
size - index);
elementData[index] = element;
size++;
}
在这个方法中我们看到他的参数有两个,一个索引,一个元素。这个方法我们相信大家都用过,就是将某元素插入到以存在的索引中,在这个方法中,我们看到,对这个索引进行了判断,并抛出了一个角标越界异常。这样做的目的在于,原因在于我们不可能对一个所以不存在的数组进行操作。随后,我们又看到了我们的熟悉方法ensureCapacity(size+1);,进行扩容之后调用system下的一个arraycopy数组复制方法。对其进行复制操作。
public static void arraycopy(Object src,
int srcPos,
Object dest,
int destPos,
int length)
}
通过查api文档,官方是这样对其解释的。
如果参数 src 和 dest 引用相同的数组对象,则复制的执行过程就好像首先将srcPos 到srcPos+length-1 位置的组件复制到一个带有 length 组件的临时数组,然后再将此临时数组的内容复制到目标数组的destPos 到destPos+length-1 位置一样。
这样说大家还可能云里雾里,那么我给大家写几个例子,大家看后就豁然开朗了。
这从原数据源中的第四个位置,复制,到目标数据数组中的起始位置为3的位置上,复制1个
private static void arraycopy(){
int[] fun ={0,1,2,3,4,5,6,7};
for (int i : fun) {
System.out.print(i);
}
System.out.println();
System.arraycopy(fun,2,fun,2+1,fun.length-2-1);
//01234567
//01423456
//然后给2角标的数组赋值。
fun[2]=4;
for (int i : fun) {
System.out.print(i);
}
}
在我这个方法中
实现过程是这样的,先生成一个长度为length的临时数组,将fun数组中srcPos
到srcPos+length-1之间的数据拷贝到临时数组中,再执行System.arraycopy(临时数组,2,fun,3,5),然后通过数组角标赋值,
elementData[index] = element;
ArrayList的简单剖析就到这儿了,感谢观看