从同一个数组创建了两个列表,修改其中一个列表会改变另一个列表。

9
我从同一个数组中创建了两个列表,并对其中一个进行了排序。当我尝试更改其中一个列表时,另一个列表也被更新了。
List<Integer> list = Arrays.asList(ar);
List<Integer> sorted = Arrays.asList(ar);
Collections.sort(sorted);
list.set(0,10000000); //changes sorted also

我花了一段时间才明白,下面提到的代码是可行的。

List<Integer> sorted = new ArrayList<Integer>(Arrays.asList(ar));

我想知道为什么我的第一个尝试失败了?我创建了两个分离的列表,为什么它们都发生了变化?Java 在这里如何分配值给变量?


“list”和“sorted”指向同一个数组,是吗? - Andrew Tobilko
1
@AndrewTobilko:但他只排序了一个列表。我会投票支持这个有趣的问题。 - Hovercraft Full Of Eels
我有点惊讶,因为自从“问题”出现(Java 1.2)以来,这似乎是第一次在SO上提出这个问题。我怀疑每个人都读过(并理解)javadoc直到现在... - Didier L
4个回答

11

根据Java文档中的Arrays.asList

返回由指定数组支持的固定大小列表。 (对返回的列表进行的更改“写入”到数组中。)此方法充当基于数组和基于集合的API之间的桥梁,与Collection.toArray()结合使用。 返回的列表是可序列化的并实现了RandomAccess

因此,当您更改列表中的内容时,它会"写入"到底层数组ar中,该数组也是在sorted中的底层数组,因此更改也反映在sorted中。

asList的代码如下:

public static <T> List<T> asList(T... a) {
    return new ArrayList<T>(a);
}

这是 java.util.Arrays.ArrayList,它具有以下定义:

ArrayList(E[] array) {
    a = Objects.requireNonNull(array);
}

重要的是,a 没有被复制,它是原始数组。 java.util.ArrayList 类有以下构造函数。

public ArrayList(Collection<? extends E> c) {
     elementData = c.toArray();
     size = elementData.length;
     // c.toArray might (incorrectly) not return Object[] (see 6260652)
     if (elementData.getClass() != Object[].class)
         elementData = Arrays.copyOf(elementData, size, Object[].class);
 }

所以在java.util.ArrayList构造函数中,我们创建每个元素的副本,在java.util.Arrays.ArrayList中则不会这样做。


2
请不要混淆java.util.Arrays.ArrayListjava.util.ArrayList。在Java 8中,它们的行为没有改变。 - Holger
@Holger,谢谢!我更新了原帖以包含这一点。 - Sunde

1

数组有其自己的ArrayList实现,它不会从toList中复制数组。


1
一个列表是对象的集合,两个列表都是相同对象的集合。set语句会改变一个对象,并且这个对象被两个列表所共享。
我不明白为什么第二个版本能够工作。

0

listsorted在第一种方法中仍然指向ar的相同内存地址,而在第二种方法中,在调用构造函数后分配了一个新的内存地址给类对象。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接