Java ArrayList复制


214

ArrayList l1的尺寸为10。我分配l1给新列表引用类型l2。威尔l1l2指向同一个ArrayList对象吗?还是ArrayList分配给对象的副本l2

使用l2引用时,如果我更新列表对象,它也会反映l1引用类型中的更改。

例如:

List<Integer> l1 = new ArrayList<Integer>();
for (int i = 1; i <= 10; i++) {
    l1.add(i);
}

List l2 = l1;
l2.clear();

除了创建2个列表对象并在集合上进行从旧到新的复制之外,没有其他方法可以将列表对象的副本分配给新的引用变量吗?

Answers:


459

是的,分配将刚刚复制l1(这是引用)l2。它们都将引用相同的对象。

但是,创建浅表副本非常容易:

List<Integer> newList = new ArrayList<>(oldList);

(仅举一个例子。)


1
是否可以高效地将一个数组列表的仅一部分复制到一个新的数组列表中。例如:将位置5到10之间的元素从一个数组列表复制到另一个新数组列表。在我的应用程序中,范围会更大。
阿什温

1
@Ashwin:好吧,这是一个O(N)操作,但是是的...您可以使用它List.subList来获取原始列表的一部分的“视图”。
乔恩·斯基特

如果数组列表嵌套(ArrayList<ArrayList<Object>>)怎么办?会递归地创建所有子ArrayList对象的副本吗?
2015年

3
@猫:不...这只是一个浅表。
乔恩·斯基特

1
@ShanikaEdiriweera:您可以使用流媒体流利地做到这一点,是的。但是棘手的部分是创建一个深层副本,大多数对象都不会提供。如果您有特定的案例,建议您提出一个详细的新问题。
乔恩·斯基特

67

13
要解释为什么这可能更可取new ArrayList<>(source);
Alex

6
@atc是进行浅表复制的另一种方法,它代替了新的ArrayList(),它使用了另一种算法,并且可用于任何List实现,而不仅仅是ArrayList,仅此
而已

14
这种方法很容易误导!实际上,它的描述是。它说:“将元素从一个源列表复制到目标位置”,但不会被复制!它们被引用,因此将只有对象的1个副本,如果它们是可变的,那么您就麻烦了
ACV

5
Java api中的任何集合类都无法进行深度克隆
Vikash

这个答案没有任何意义。Collections.copy根本不是替代new ArrayList<>(source)。什么Collections.copy实际上做的是假设destination.size()至少是一样大的source.size(),然后复制指数范围内按指数使用的set(int,E)方法。该方法不会新元素添加到目标。如果Javadoc还不够清楚,请参考源代码。
Radiodef

35

是的,l1并且l2将指向相同的引用,相同的对象。

如果要基于另一个ArrayList创建一个新的ArrayList,请执行以下操作:

List<String> l1 = new ArrayList<String>();
l1.add("Hello");
l1.add("World");
List<String> l2 = new ArrayList<String>(l1); //A new arrayList.
l2.add("Everybody");

结果将l1仍然是2个元素,并且l2将有3个元素。


能否请您解释之间的差异List<String> l2 = new ArrayList<String>(l1)List<String> l2 = l1
MortalMan 2015年

@MortalMan的区别在于l2 = new ArrayList <String>(l1)是一个全新的对象,修改l2不会影响l1,而List <String> l2 = l1则不是在创建新对象,而只是引用相同的对象对象为l1,因此在这种情况下,执行l2.add(“ Everybody”),l1.size()和l2.size()之类的操作将返回3,因为两者都引用同一个对象。
Alfredo Osorio

19

将值从src ArrayList复制到dest Arraylist的另一种便捷方法如下:

ArrayList<String> src = new ArrayList<String>();
src.add("test string1");
src.add("test string2");
ArrayList<String> dest= new ArrayList<String>();
dest.addAll(src);

这是值的实际复制,而不仅仅是引用的复制。


10
我不完全确定这是正确的。我的测试显示了相反的结果(仍引用相同的对象)
invertigo 2013年

该解决方案使用的ArrayList时ArrayAdapter为我工作
albanx

1
这个答案是错误的。addAll()只是复制引用,如invertigo所说。这不是深度复制。
jk7

对于ArrayList <String>,此答案是可以接受的,因为String是不可变的,但请以OP的示例ArraList <Integer>进行尝试,您将看到它只是在复制引用。
jk7

我猜只是我的一天。事实证明,诸如Integer和Long的类也是不可变的,因此Harshal的答案适用于诸如ArrayList <Integer>和ArrayList <String>的简单情况。它失败的地方是针对不可变的复杂对象。
jk7

8

有一个方法addAll(),用于将一个ArrayList复制到另一个。

例如,您有两个数组列表:sourceListtargetList,请使用下面的代码。

targetList.addAll(sourceList);


它也只是复制参考。
维卡什

4

Java不传递对象,而是将引用(指针)传递给对象。所以是的,l2和l1是指向同一对象的两个指针。

如果需要两个具有相同内容的不同列表,则必须进行显式复制。


3
您如何制作“显式副本”?我想您是在谈论深层副本?
Cin316 2013年

1

List.copyOf list不可修改的清单

你问:

没有其他方法可以分配列表的副本

Java 9带来了List.of使用文字来创建不可修改List的未知具体类的方法。

LocalDate today = LocalDate.now( ZoneId.of( "Africa/Tunis" ) ) ;
List< LocalDate > dates = List.of( 
    today.minusDays( 1 ) ,  // Yesterday
    today ,                 // Today
    today.plusDays( 1 )     // Tomorrow
);

除此之外,我们也得到了List.copyOf。此方法也返回不可修改List的未知具体类。

List< String > colors = new ArrayList<>( 4 ) ;          // Creates a modifiable `List`. 
colors.add ( "AliceBlue" ) ;
colors.add ( "PapayaWhip" ) ;
colors.add ( "Chartreuse" ) ;
colors.add ( "DarkSlateGray" ) ;
List< String > masterColors = List.copyOf( colors ) ;   // Creates an unmodifiable `List`.

“不可修改的”是指列表中元素的数量,每个插槽中作为元素包含的对象引用是固定的。您不能添加,删除或替换元素。但是保存在每个元素中的对象引用可能是可变的,也可能不是可变的

colors.remove( 2 ) ;          // SUCCEEDS. 
masterColors.remove( 2 ) ;    // FAIL - ERROR.

看到此代码在IdeOne.com上实时运行

date.toString():[2020-02-02、2020-02-03、2020-02-04]

colors.toString():[AliceBlue,PapayaWhip,DarkSlateGray]

masterColors.toString():[AliceBlue,PapayaWhip,Chartreuse,DarkSlateGray]

您询问有关对象引用的问题。正如其他人所说,如果创建一个列表并将其分配给两个引用变量(指针),则仍然只有一个列表。两者都指向同一列表。如果使用任一指针修改列表,则两个指针稍后将看到更改,因为内存中只有一个列表。

因此,您需要复制列表。如果您希望该副本不可修改,请使用List.copyOf此答案中讨论的方法。在这种方法中,您最终得到两个单独的列表,每个列表都包含对相同内容对象的引用。例如,在上面的示例中,使用String对象表示颜色,颜色对象在内存中的某个位置浮动。这两个列表包含指向相同颜色对象的指针。这是一张图。

在此处输入图片说明

第一个列表colors是可修改的。这意味着可以删除某些元素,如上面的代码所示,其中我们删除了原始的第3个元素Chartreuse(索引2 =序数3)。并且可以添加元素。元素可以更改为指向String诸如OliveDrab或的其他元素CornflowerBlue

相反,的四个元素masterColors是固定的。没有删除,没有添加,也没有替代另一种颜色。该List实现是不可修改的。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.