文章目录
Lsit中数据复制问题1.1浅拷贝1.2深拷贝1.3 最终结论Lsit中数据复制问题
这是由一道开放式面试题引发的文章,题目:加入内存足够大,一个集合中有100万条数据,怎么高效的把集合中的数据复制到另外一个集合
1.1浅拷贝
java 中复制分为浅拷贝和深拷贝
如果考察浅拷贝:直接使用clone方法
System.out.println("测试开始时");List<String> a=new ArrayList<String>(10000000);int i=1;for(int x = 1; x < 10000000; x = x+1){a.add(Integer.toString(x));}List<String> b=new ArrayList<String>(10000000);List<String> c=new ArrayList<String>(10000000);long begintime = System.nanoTime();b= (List<String>) ((ArrayList<String>) a).clone(); //浅拷贝
明显,问题没有这么简单
深度拷贝的话最简单就是遍历,这个基本都知道,自己实现遍历性能不会是最高的,开始思考
collections包含的方法
Collections.copy(c,a);
但这种方法具有局限,List c的size 要>= a.size()
并且根据代码这种方式也是浅拷贝
接下来想,如果是List
可以使用addall()
原理是数据拷贝,使用了java的native方法复制内存
同样也是浅拷贝
经过对比集中浅拷贝
java中提供了流式计算
d = a.stream().collect(Collectors.toList());
经过实际验证:
addall()和collections.copy(a,b)
消耗时间接近,是比较好的复制方法,其中addall()略微好于collections
一般java的高效的集合类都在
java.util.concurrent.*;
分析代码:
long begintime5 = System.nanoTime();CopyOnWriteArrayList m=new CopyOnWriteArrayList(a);long endtime5 = System.nanoTime();long costTime5 = (endtime5 - begintime5)/1000;System.out.println("测试结束5: "+costTime5);
底层原理分析,看代码
/*** Creates a list containing the elements of the specified* collection, in the order they are returned by the collection's* iterator.** @param c the collection of initially held elements* @throws NullPointerException if the specified collection is null*/public CopyOnWriteArrayList(Collection<? extends E> c) {Object[] elements;if (c.getClass() == CopyOnWriteArrayList.class)elements = ((CopyOnWriteArrayList<?>)c).getArray();else {elements = c.toArray();// c.toArray might (incorrectly) not return Object[] (see 6260652)if (elements.getClass() != Object[].class)elements = Arrays.copyOf(elements, elements.length, Object[].class);}setArray(elements);}
这段显示,调用了Arrays.copuOf()
/*** Copies the specified array, truncating or padding with nulls (if necessary)* so the copy has the specified length. For all indices that are* valid in both the original array and the copy, the two arrays will* contain identical values. For any indices that are valid in the* copy but not the original, the copy will contain <tt>null</tt>.* Such indices will exist if and only if the specified length* is greater than that of the original array.* The resulting array is of the class <tt>newType</tt>.** @param <U> the class of the objects in the original array* @param <T> the class of the objects in the returned array* @param original the array to be copied* @param newLength the length of the copy to be returned* @param newType the class of the copy to be returned* @return a copy of the original array, truncated or padded with nulls*to obtain the specified length* @throws NegativeArraySizeException if <tt>newLength</tt> is negative* @throws NullPointerException if <tt>original</tt> is null* @throws ArrayStoreException if an element copied from*<tt>original</tt> is not of a runtime type that can be stored in*an array of class <tt>newType</tt>* @since 1.6*/public static <T,U> T[] copyOf(U[] original, int newLength, Class<? extends T[]> newType) {@SuppressWarnings("unchecked")T[] copy = ((Object)newType == (Object)Object[].class)? (T[]) new Object[newLength]: (T[]) Array.newInstance(newType.getComponentType(), newLength);System.arraycopy(original, 0, copy, 0,Math.min(original.length, newLength));return copy;}
接下来调用了
System.arraycopy(original, 0, copy, 0,
Math.min(original.length, newLength));
看看最后:
public static native void arraycopy(Object src, int srcPos,Object dest, int destPos,int length);
java的native 方法,效率最高
本质和collection的clone的方法逻辑一致
1.2深拷贝
集合的深度拷贝,除了遍历还有一种是序列化和反序列,这种首先排除在外,接下来看看还有没有其他方式
查询了资料,木有发现更好的深拷贝方法
经过实践对比,序列化、反序列化是效率最高的办法
1.3 最终结论
public static <T> List<T> depCopy(List<T> srcList) {ByteArrayOutputStream byteOut = new ByteArrayOutputStream();try {ObjectOutputStream out = new ObjectOutputStream(byteOut);out.writeObject(srcList);ByteArrayInputStream byteIn = new ByteArrayInputStream(byteOut.toByteArray());ObjectInputStream inStream = new ObjectInputStream(byteIn);List<T> destList = (List<T>) inStream.readObject();return destList;} catch (IOException e) {e.printStackTrace();} catch (ClassNotFoundException e) {e.printStackTrace();}return null;}
以上针对问题,初步研究。
参考1:/u010648159/article/details/79144154
参考2:/demonliuhui/article/details/54572908