Java ArrayList副本

我有一个ArrayList l1的大小为10。我将l1赋值给新的列表引用类型l2l1l2是否指向同一个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个列表对象,并在从旧到新的集合上进行复制外,是否没有其他方法将列表对象的副本分配给新的引用变量?

462986 次浏览

是的,赋值只是将l1价值(这是一个引用)复制到l2。它们都指向同一个对象。

创建一个浅拷贝非常简单:

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

(这只是一个例子。)

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

如果你需要两个内容相同的不同列表,你必须做一个显式副本。

是的,l1l2将指向同一个引用,同一个对象。

如果你想在另一个数组列表的基础上创建一个新的数组列表,你可以这样做:

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个元素。

将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);

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

有一个方法addAll (),用于将一个数组列表复制到另一个数组列表。

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

targetList.addAll (sourceList);

List.copyOf➙不可修改列表

你问:

是否没有其他方法分配列表的副本

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上运行

dates.toString(): [2020-02-02, 2020-02-03, 2020-02-04]

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

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

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

所以你需要复制一份清单。如果你想让该副本不可修改,请使用本答案中讨论的List.copyOf方法。在这种方法中,您最终会得到两个单独的列表,每个列表的元素都包含对相同内容对象的引用。例如,在上面使用String对象表示颜色的例子中,颜色对象漂浮在内存的某个地方。这两个列表包含指向相同颜色对象的指针。这是一个图表。

enter image description here

第一个列表colors是可修改的。这意味着一些元素可以被删除,如上面的代码所示,其中我们删除了原来的第3个元素Chartreuse (index of 2 = ordinal 3)。并且可以添加元素。元素可以改变为指向其他String,如OliveDrabCornflowerBlue

相反,masterColors的四个元素是固定的。不能去除,不能添加,也不能替换其他颜色。这个List实现是不可修改的。

只是为了完成: 上面所有的答案都是浅层复制——保持原始对象的引用。如果你想要一个深度拷贝,你的(引用)类在列表中必须实现一个 克隆/复制方法,它提供单个对象的深度副本。然后你可以使用:

newList.addAll(oldList.stream().map(s->s.clone()).collect(Collectors.toList()));

试试这个数组列表 它工作良好

ArrayList<Integer> oldList = new ArrayList<>(Integer);
oldList.add(1);
oldList.add(2);


ArrayList<Integer> newList = new ArrayList<>(oldList);
// now newList contains 1, 2