276

I have an ArrayList l1 of size 10. I assign l1 to new list reference type l2. Will l1 and l2 point to same ArrayList object? Or is a copy of the ArrayList object assigned to l2?

When using the l2 reference, if I update the list object, it reflects the changes in the l1 reference type also.

For example:

List<Integer> l1 = new ArrayList<Integer>();
for (int i = 1; i <= 10; i++) {
    l1.add(i);
}

List l2 = l1;
l2.clear();

Is there no other way to assign a copy of a list object to a new reference variable, apart from creating 2 list objects, and doing copy on collections from old to new?

10 Answers 10

570

Yes, assignment will just copy the value of l1 (which is a reference) to l2. They will both refer to the same object.

Creating a shallow copy is pretty easy though:

List<Integer> newList = new ArrayList<>(oldList);

(Just as one example.)

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

16 Comments

Is it possible to copy only a part of an arraylist to a new arraylist, Efficiently. for eg: copy elements between position 5 and 10 from one arraylist to another new arraylist. In my application the range would be much bigger.
@Ashwin: Well it's an O(N) operation, but yes... you can use List.subList to get a "view" onto a section of the original list.
what if the array lists are nested (ArrayList<ArrayList<Object>>)? would this recursively create copies of all children ArrayList objects?
@Cat: No... This is only a shallow copy.
@ShanikaEdiriweera: You could do it in a fluent way with streams, yes. But the tricky part is creating a deep copy, which most objects won't provide. If you have a specific case in mind, I suggest you ask a new question with details.
|
74

Try to use Collections.copy(destination, source);

5 Comments

Care to explain why this might be preferable to new ArrayList<>(source);?
This method is very misleading! Actually, it's description is. It says: "copies elements from one source list into the destination", but they are not copied! They are referenced so there will only be 1 copy of the objects and if they are mutable, you're in trouble
nowhere in java-api deep cloning is done by any collection class
This answer doesn't make a whole lot of sense. Collections.copy is not at all an alternative to new ArrayList<>(source). What Collections.copy actually does is assume that destination.size() is at least as big as source.size(), and then copy the range index-by-index using the set(int,E) method. The method doesn't add new elements to the destination. Refer to the source code if it's not clear enough from the Javadoc.
This method doesn't work. If you need to create a copy then use new ArrayList<>(oldList);
36

Yes l1 and l2 will point to the same reference, same object.

If you want to create a new ArrayList based on the other ArrayList you do this:

List<String> l1 = new ArrayList<String>();
l1.add("Hello");
l1.add("World");
List<String> l2 = new ArrayList<String>(l1); //A new arrayList.
l2.add("Everybody");

The result will be l1 will still have 2 elements and l2 will have 3 elements.

2 Comments

Can you please explain the difference between List<String> l2 = new ArrayList<String>(l1) and List<String> l2 = l1?
@MortalMan the difference is that l2 = new ArrayList<String>(l1) is an entirely new object and modifying l2 doesn't affect l1, whereas List<String> l2 = l1 you are not creating a new object but just referencing the same object as l1, so in this case doing an operation such as l2.add("Everybody"), l1.size() and l2.size() will return 3 because both are referencing the same object.
19

Another convenient way to copy the values from src ArrayList to dest Arraylist is as follows:

ArrayList<String> src = new ArrayList<String>();
src.add("test string1");
src.add("test string2");
ArrayList<String> dest= new ArrayList<String>();
dest.addAll(src);

This is actual copying of values and not just copying of reference.

5 Comments

i'm not entirely sure this is accurate. my test shows the opposite (still referencing same object)
this solution worked for me when using ArrayList with ArrayAdapter
This answer is wrong. addAll() just copies the references as invertigo said. This is not a deep copy.
For an ArrayList<String> this answer is acceptable because String is immutable, but try it with the OP's example, an ArraList<Integer>, and you'll see it is just copying references.
Just not my day I guess. It turns out classes such as Integer and Long are also immutable, so Harshal's answer works for simple cases such as ArrayList<Integer> and ArrayList<String>. Where it fails is for complex objects that are not immutable.
11

There is a method addAll() which will serve the purpose of copying One ArrayList to another.

For example you have two Array Lists: sourceList and targetList, use below code.

targetList.addAll(sourceList);

1 Comment

it also just copies references.
4

Java doesn't pass objects, it passes references (pointers) to objects. So yes, l2 and l1 are two pointers to the same object.

You have to make an explicit copy if you need two different list with the same contents.

1 Comment

How do you make "an explicit copy"? I suppose you're talking about a deep copy?
2

1 :you can use addAll()

newList.addAll(oldList);

2 : you can copy new arraylist if you create!

ArrayList<String> newList = new ArrayList<>(OldList);

Comments

2

List.copyOf ➙ unmodifiable list

You asked:

Is there no other way to assign a copy of a list

Java 9 brought the List.of methods for using literals to create an unmodifiable List of unknown concrete class.

LocalDate today = LocalDate.now( ZoneId.of( "Africa/Tunis" ) ) ;
List< LocalDate > dates = List.of( 
    today.minusDays( 1 ) ,  // Yesterday
    today ,                 // Today
    today.plusDays( 1 )     // Tomorrow
);

Along with that we also got List.copyOf. This method too returns an unmodifiable List of unknown concrete class.

List< String > colors = new ArrayList<>( 4 ) ;          // Creates a modifiable `List`. 
colors.add ( "AliceBlue" ) ;
colors.add ( "PapayaWhip" ) ;
colors.add ( "Chartreuse" ) ;
colors.add ( "DarkSlateGray" ) ;
List< String > masterColors = List.copyOf( colors ) ;   // Creates an unmodifiable `List`.

By “unmodifiable” we mean the number of elements in the list, and the object referent held in each slot as an element, is fixed. You cannot add, drop, or replace elements. But the object referent held in each element may or may not be mutable.

colors.remove( 2 ) ;          // SUCCEEDS. 
masterColors.remove( 2 ) ;    // FAIL - ERROR.

See this code run live at IdeOne.com.

dates.toString(): [2020-02-02, 2020-02-03, 2020-02-04]

colors.toString(): [AliceBlue, PapayaWhip, DarkSlateGray]

masterColors.toString(): [AliceBlue, PapayaWhip, Chartreuse, DarkSlateGray]

You asked about object references. As others said, if you create one list and assign it to two reference variables (pointers), you still have only one list. Both point to the same list. If you use either pointer to modify the list, both pointers will later see the changes, as there is only one list in memory.

So you need to make a copy of the list. If you want that copy to be unmodifiable, use the List.copyOf method as discussed in this Answer. In this approach, you end up with two separate lists, each with elements that hold a reference to the same content objects. For example, in our example above using String objects to represent colors, the color objects are floating around in memory somewhere. The two lists hold pointers to the same color objects. Here is a diagram.

enter image description here

The first list colors is modifiable. This means that some elements could be removed as seen in code above, where we removed the original 3rd element Chartreuse (index of 2 = ordinal 3). And elements can be added. And the elements can be changed to point to some other String such as OliveDrab or CornflowerBlue.

In contrast, the four elements of masterColors are fixed. No removing, no adding, and no substituting another color. That List implementation is unmodifiable.

1 Comment

That is a newest version and a excellent answer!
1

Just for completion: All the answers above are going for a shallow copy - keeping the reference of the original objects. I you want a deep copy, your (reference-) class in the list have to implement a clone / copy method, which provides a deep copy of a single object. Then you can use:

newList.addAll(oldList.stream().map(s->s.clone()).collect(Collectors.toList()));

Comments

0

Try this for ArrayList It works fine

ArrayList<Integer> oldList = new ArrayList<>(Integer);
oldList.add(1);
oldList.add(2);

ArrayList<Integer> newList = new ArrayList<>(oldList);
// now newList contains 1, 2

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.