2

While inspecting ArrayList API, I noticed something that looks strange.

Indeed, here the the ArrayList constructor implementation with a Collection passed as argument :

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

and here the equivalent into the HashSet Class :

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

So, we can notice that the ArrayList one used a COPY (Arrays.copyOf) of elements provided by the collection in parameter whereas the HashSet one, use addAll() method.

And of course, addAll() method doesn't copy elements but just add references to the HashSet collection.

I find this subtil difference "dangerous" for caller that ignores it.

One could expect a collection with SAME references, another one who read ArrayList API well would expect a COPY of elements from original Collection.

Why didn't Sun provide same concept for those Collections subclasses ?

3 Answers 3

8

ArrayList one used a COPY (Arrays.copyOf) of elements provided by the collection in parameter whereas the HashSet one, use addAll() method.

No, Arrays.copyOf only copies the array, but not objects this array points to. The objects aren't cloned. That being said both constructors behave the same - they will contain references to the same objects as the original collection. Modifying an object in one collection will modify it in the other (because it is the same object).

Also note that Arrays.copyOf() is only used in some circumstances.

Sign up to request clarification or add additional context in comments.

3 Comments

+1 The only purpose of the copy is so that adding entries to the original source array doesn't also affect your ArrayList.
@mellamokb: not even that, c.toArray() is guaranteed to return new array, even when called on ArrayList.
@Tomasz Nurkiewicz Thanks :) So I can understand now the reason for which HashSet doesn't make an arrayCopy too => In HashSet, there's the concept of Hashing and so without entering into adding Process (that calculates hash and choose the correponsing table index for each element), there is no need to envisage position of elements in advance.
3

Both ArrayList and HashSet will copy only the references, not the actual objects that those references refer to.

In Java, a variable of a non-primitive type is a reference to an object. If you have an array of those, then Arrays.copyOf copies only the references - not the objects that those references refer to.

Comments

1

The collections will have the same references. If you have a list of three objects, A, B, C, and copy that list, the new copy will also reference those identical 3 objects. These constructors are both shallow, they don't touch the original objects at all.

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

Gives:

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] 

You'll notice that all of the collections reference the identical objects. (The HashSet is in a different order.)

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.