java 集合的深度复制_java 集合 深度复制多种实现方式和使用注意事项

今天遇到一个问题:对一个集合进行深度复制

最先想到的是利用集合工具类的copy()方法,但是它出现了一些问题

Collections.copy使用注意事项

示例代码:

import java.util.ArrayList;

import java.util.Arrays;

import java.util.Collections;

import java.util.List;

public class CollectionsTest {

public static void main(String[] args) {

// 创建一个集合list

String[] array = { "1", "2", "3", "4", "5" };

List list = Arrays.asList(array);

// 创建一个新的集合dest

List dest = new ArrayList();

// 把list集合中的元素复制到dest集合中

Collections.copy(dest, list);

System.out.println(dest);

}

}

运行结果:

Exception in thread "main" java.lang.IndexOutOfBoundsException: Source does not fit in dest

at java.util.Collections.copy(Collections.java:556)

at com.CollectionsTest.main(CollectionsTest.java:17)

源码分析:

/**

* Copies all of the elements from one list into another. After the

* operation, the index of each copied element in the destination list

* will be identical to its index in the source list. The destination

* list must be at least as long as the source list. If it is longer, the

* remaining elements in the destination list are unaffected.

*

* This method runs in linear time.

*

* @param the class of the objects in the lists

* @param dest The destination list.

* @param src The source list.

* @throws IndexOutOfBoundsException if the destination list is too small

* to contain the entire source List.

* @throws UnsupportedOperationException if the destination list's

* list-iterator does not support the set operation.

*/

public static void copy(List super T> dest, List extends T> src) {

int srcSize = src.size();

if (srcSize > dest.size())

throw new IndexOutOfBoundsException("Source does not fit in dest");

if (srcSize < COPY_THRESHOLD ||

(src instanceof RandomAccess && dest instanceof RandomAccess)) {

for (int i=0; i

dest.set(i, src.get(i));

} else {

ListIterator super T> di=dest.listIterator();

ListIterator extends T> si=src.listIterator();

for (int i=0; i

di.next();

di.set(si.next());

}

}

}

96531d22aba79aecb72e637bf76b5c6f.png

结论: dest.size()的长度不能小于srcSize();目标列表必须至少与源列表一样长。如果更长,则目标列表中的其余元素不受影响。

修改代码,对dest初始列表容量:

public class CollectionsTest {

public static void main(String[] args) {

// 创建一个集合list

String[] array = { "1", "2", "3", "4", "5" };

List list = Arrays.asList(array);

// 创建一个新的集合dest

List dest = new ArrayList(5);

// 把list集合中的元素复制到dest集合中

Collections.copy(dest, list);

System.out.println(dest);

}

}

运行结果:

000c85c70365154c6b7bc32e7bdbc67f.png

问题依旧出现,当打印dest的size,结果为 0

分析ArrayList源码:

/**

* Constructs an empty list with the specified initial capacity.

*

* @param initialCapacity the initial capacity of the list

* @throws IllegalArgumentException if the specified initial capacity

* is negative

*/

public ArrayList(int initialCapacity) {

if (initialCapacity > 0) {

this.elementData = new Object[initialCapacity];

} else if (initialCapacity == 0) {

this.elementData = EMPTY_ELEMENTDATA;

} else {

throw new IllegalArgumentException("Illegal Capacity: "+

initialCapacity);

}

}

结论:构造具有指定初始容量的空列表,实际上没有定义元素,元素数量为0

解决方案:

一个长度是原集合大小的数组,元素的个数是size,元素初始值为null。

public class CollectionsTest {

public static void main(String[] args) {

// 创建一个集合list

String[] array = { "1", "2", "3", "4", "5" };

List list = Arrays.asList(array);

// 创建一个新的集合dest

List dest = Arrays.asList(new String[list.size()]);

// 把list集合中的元素复制到dest集合中

Collections.copy(dest, list);

System.out.println(dest);

}

}

运行结果:

[1, 2, 3, 4, 5]

Arrays.asList()使用注意事项

Arrays.asList()

Arrays是java容器相关操作的工具类,asList()方法将数组转换为集合。

在使用工具类Arrays.asList()把数组转换成集合时,不能使用其修改集合相关的方法,否则会抛出UnsupportOperationException异常。

示例代码:

public class CollectionsTest {

public static void main(String[] args) {

// 创建一个集合list

String[] array = { "1", "2", "3", "4", "5" };

List list = Arrays.asList(array);

// 创建一个新的集合dest

List dest = Arrays.asList(new String[list.size()]);

// 把list集合中的元素复制到dest集合中

Collections.copy(dest, list);

dest.remove("1");

System.out.println(dest);

}

}

运行结果:

Exception in thread "main" java.lang.UnsupportedOperationException

at java.util.AbstractList.remove(AbstractList.java:161)

at java.util.AbstractList$Itr.remove(AbstractList.java:374)

at java.util.AbstractCollection.remove(AbstractCollection.java:293)

at com.CollectionsTest.main(CollectionsTest.java:19)

源码分析:

private static class ArrayList extends AbstractList

implements RandomAccess, java.io.Serializable

{

private static final long serialVersionUID = -2764017481108945198L;

private final E[] a;

ArrayList(E[] array) {

a = Objects.requireNonNull(array);

}

@Override

public int size() {

return a.length;

}

@Override

public Object[] toArray() {

return a.clone();

}

@Override

@SuppressWarnings("unchecked")

public T[] toArray(T[] a) {

int size = size();

if (a.length < size)

return Arrays.copyOf(this.a, size,

(Class extends T[]>) a.getClass());

System.arraycopy(this.a, 0, a, 0, size);

if (a.length > size)

a[size] = null;

return a;

}

@Override

public E get(int index) {

return a[index];

}

@Override

public E set(int index, E element) {

E oldValue = a[index];

a[index] = element;

return oldValue;

}

@Override

public int indexOf(Object o) {

E[] a = this.a;

if (o == null) {

for (int i = 0; i < a.length; i++)

if (a[i] == null)

return i;

} else {

for (int i = 0; i < a.length; i++)

if (o.equals(a[i]))

return i;

}

return -1;

}

@Override

public boolean contains(Object o) {

return indexOf(o) != -1;

}

@Override

public Spliterator spliterator() {

return Spliterators.spliterator(a, Spliterator.ORDERED);

}

@Override

public void forEach(Consumer super E> action) {

Objects.requireNonNull(action);

for (E e : a) {

action.accept(e);

}

}

@Override

public void replaceAll(UnaryOperator operator) {

Objects.requireNonNull(operator);

E[] a = this.a;

for (int i = 0; i < a.length; i++) {

a[i] = operator.apply(a[i]);

}

}

@Override

public void sort(Comparator super E> c) {

Arrays.sort(a, c);

}

}

8e1da4d977410665f365c966c12be71e.png

结论:

由Arrays.asList() 返回的是Arrays的内部类ArrayList, 而不是java.util.ArrayList。

Arrays的内部类ArrayList和java.util.ArrayList都是继承AbstractList抽象类,都包含:remove、add等方法。

AbstractList中默认实现throw UnsupportedOperationException而且不作任何操作。

java.util.ArrayList重新实现了这些方法

Arrays的内部类ArrayList没有重新,所以会抛出异常。

解决方案:

参照下方使用构造方法复制

其他集合深度复制方法:

遍历循环复制

使用构造方法复制

List dest = new ArrayList(list);

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值