2

在检查 ArrayList API 时,我注意到一些看起来很奇怪的东西。

实际上,这里是 ArrayList 构造函数实现,其中 Collection 作为参数传递:

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

这里相当于 HashSet 类:

public HashSet(Collection<? extends E> c) {
        map = new HashMap<>(Math.max((int) (c.size()/.75f) + 1, 16));
        addAll(c);
}

因此,我们可以注意到 ArrayList 使用了由集合 in 参数提供的元素的 COPY (Arrays.copyOf),而 HashSet 使用 addAll() 方法。

当然,addAll() 方法不会复制元素,而只是添加对 HashSet 集合的引用。

对于忽略它的呼叫者,我发现这种细微的差异是“危险的”。

一个人可能会期望一个具有相同引用的集合,另一个阅读 ArrayList API 的人会期望一个原始集合中元素的副本。

为什么 Sun 没有为这些 Collections 子类提供相同的概念?

4

3 回答 3

8

ArrayList 一使用参数集合提供的元素的 COPY (Arrays.copyOf),而 HashSet 一使用 addAll() 方法。

不,Arrays.copyOf只复制数组,但不复制该数组指向的对象。不会克隆对象。话虽如此,两个构造函数的行为相同 - 它们将包含对与原始集合相同的对象的引用。在一个集合中修改一个对象将在另一个集合中修改它(因为它是同一个对象)。

另请注意,Arrays.copyOf()仅在某些情况下使用。

于 2012-04-14T20:52:13.277 回答
3

两者ArrayListHashSet都将仅复制引用,而不是这些引用所引用的实际对象。

在 Java 中,非原始类型的变量是对对象的引用。如果你有一个数组,那么Arrays.copyOf只复制引用 - 而不是这些引用引用的对象。

于 2012-04-14T20:52:52.120 回答
1

这些集合将具有相同的引用。如果您有一个包含三个对象 A、B、C 的列表,并复制该列表,则新副本还将引用这三个相同的对象。这些构造函数都很浅,它们根本不接触原始对象。

public static void main(String args[]) {
    ArrayList l = new ArrayList();
    Object a = new Object();
    Object b = new Object();
    Object c = new Object();
    l.add(a);
    l.add(b);
    l.add(c);

    ArrayList k = new ArrayList(l);
    HashSet h = new HashSet(l);
    System.out.println(a);
    System.out.println(b);
    System.out.println(c);

    System.out.println(l);
    System.out.println(k);
    System.out.println(h);
}

给出:

java.lang.Object@43256ea2
java.lang.Object@4e82701e
java.lang.Object@558ee9d6
[java.lang.Object@43256ea2, java.lang.Object@4e82701e, java.lang.Object@558ee9d6]
[java.lang.Object@43256ea2, java.lang.Object@4e82701e, java.lang.Object@558ee9d6]
[java.lang.Object@4e82701e, java.lang.Object@43256ea2, java.lang.Object@558ee9d6]

您会注意到所有集合都引用了相同的对象。(HashSet 的顺序不同。)

于 2012-04-14T20:55:49.353 回答