ArrayList(Collection c)VS HashSet(Collection c)

时间:2012-04-14 20:44:27

标签: collections java

在检查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使用了参数集合中提供的COPY(Arrays.copyOf)元素,而HashSet则使用了addAll()方法。

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

对于忽略它的调用者,我发现这个subtil的区别是“危险的”。

人们可以期待一个带有SAME引用的集合,另一个读取ArrayList API的人会期望从原始集合中复制元素。

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

3 个答案:

答案 0 :(得分:8)

  

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

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

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

答案 1 :(得分:3)

ArrayListHashSet都只会复制引用,而不会复制这些引用所引用的实际对象。

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

答案 2 :(得分:1)

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

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的顺序不同。)