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 ?
No,
Arrays.copyOfonly 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.