采摘处:http://blog.youkuaiyun.com/sutaizi/article/details/6607123
问题是这样产生的,网上一哥们发了一个面试题:
ListA 里面有 1 2 3
ListB里面有 4 5 6
让ListA变成 1 2 3 4 5 6
我觉得很简单 ,就说用for循环遍历 添加就好了。结果面试官说
答案是使用addAll方法,因为这样效率高:
我表示很费解,于是查阅了资料。
得出以下结论:
在小数据量时,for循环效率高,大数据量时addAll方法效率高:
原因如下:
ArrayList的addAll的实现为:
- public boolean addAll(Collection 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;
- }
很显然。。在拷贝数组时使用了
arraycopy 这个方法。这个方法是使用拷贝内存的做法 ,效率比遍历数组块很多。
首先找到数据源 然后将该段内存拷贝。
当然值得注意的是,这个函数中还使用了toArray方法,这个方法是 要遍历操作的
但是如果需要多次遍历,那么addAll还是在性能上会获取优势的. .
下面是网上的一个测试 在20组数据时 还是 for效率高,但是在大数据量的时候 arraycopy 方法就明显占优势了。
http://www.exam8.com/computer/djks/dj2/Java/ziliao/200810/1314435.htmlhttp://www.exam8.com/computer/djks/dj2/Java/ziliao/200810/1314435.html
另外:
arraycopy的定义是这样的
public static native void arraycopy(Object src, int srcPos, Object dest, int destPos,int length);
native关键字的意思是 这个函数的源码在JDK中没有的。但是他调用的是本地计算机中的函数
这个函数是C,或者C++写完的,编译成DLL。 java调用。所以效率比for循环要块。
综上所述 :为什么在大数据量时使用addall方法效率快?
1.使用内存拷贝,移动数据。
2.本地函数,执行效率高。
那小数据量时呢?
以上2点都不明显,并且首先要调用toArray方法,在小数据量时,效果没有for来的好。
采摘者:
/**
* Adds the objects in the specified collection to this {@code ArrayList}.
*
* @param collection
* the collection of objects.
* @return {@code true} if this {@code ArrayList} is modified, {@code false}
* otherwise.
*/
@Override public boolean addAll(Collection<? extends E> collection) {
Object[] newPart = collection.toArray();
int newPartSize = newPart.length;
if (newPartSize == 0) {
return false;
}
Object[] a = array;
int s = size;
int newSize = s + newPartSize; // If add overflows, arraycopy will fail
if (newSize > a.length) {
int newCapacity = newCapacity(newSize - 1); // ~33% growth room
Object[] newArray = new Object[newCapacity];
System.arraycopy(a, 0, newArray, 0, s);
array = a = newArray;
}
System.arraycopy(newPart, 0, a, s, newPartSize);
size = newSize;
modCount++;
return true;
}
/**
* Inserts the objects in the specified collection at the specified location
* in this List. The objects are added in the order they are returned from
* the collection's iterator.
*
* @param index
* the index at which to insert.
* @param collection
* the collection of objects.
* @return {@code true} if this {@code ArrayList} is modified, {@code false}
* otherwise.
* @throws IndexOutOfBoundsException
* when {@code location < 0 || > size()}
*/
@Override
public boolean addAll(int index, Collection<? extends E> collection) {
int s = size;
if (index > s || index < 0) {
throwIndexOutOfBoundsException(index, s);
}
Object[] newPart = collection.toArray();
int newPartSize = newPart.length;
if (newPartSize == 0) {
return false;
}
Object[] a = array;
int newSize = s + newPartSize; // If add overflows, arraycopy will fail
if (newSize <= a.length) {
System.arraycopy(a, index, a, index + newPartSize, s - index);
} else {
int newCapacity = newCapacity(newSize - 1); // ~33% growth room
Object[] newArray = new Object[newCapacity];
System.arraycopy(a, 0, newArray, 0, index);
System.arraycopy(a, index, newArray, index + newPartSize, s-index);
array = a = newArray;
}
System.arraycopy(newPart, 0, a, index, newPartSize);
size = newSize;
modCount++;
return true;
}
本文探讨了在Java中使用ArrayList的addAll方法与for循环添加集合元素的效率对比。通过源码分析,阐述了addAll方法利用arraycopy进行内存拷贝的优势,并讨论了不同数据量下两种方法的性能差异。
813

被折叠的 条评论
为什么被折叠?



