ArrayList的源码简单分析分析

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的简单剖析就到这儿了,感谢观看

猜你喜欢

转载自blog.csdn.net/arryluo123/article/details/70194650