271

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?

TylerH
  • 20,799
  • 66
  • 75
  • 101
user309281
  • 3,025
  • 2
  • 18
  • 18

10 Answers10

562

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.)

Fritz Duchardt
  • 11,026
  • 4
  • 41
  • 60
Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • 1
    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 Oct 16 '12 at 09:46
  • 1
    @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. – Jon Skeet Oct 16 '12 at 10:30
  • what if the array lists are nested `(ArrayList>)`? would this recursively create copies of all children ArrayList objects? – Cat Feb 24 '15 at 23:00
  • 3
    @Cat: No... This is only a shallow copy. – Jon Skeet Feb 24 '15 at 23:01
  • ah got it, so if you don't want to touch the original objects you'd have to manually iterate through each child ArrayList and create copies. thanks! – Cat Feb 25 '15 at 00:59
  • @JonSkeet is shallow copying an ArrayList to a HashSet like this also O(1)? `Set newSet = new HashSet(oldList);` – terbubbs Apr 27 '16 at 16:10
  • @terbubbs: When you say "also O(1)" - nothing I've suggested is O(1). But I'd expect that code to be O(n), just like creating a shallow list copy, unless you have a lot of hash collisions. – Jon Skeet Apr 27 '16 at 16:11
  • New list's elements will point to old elements! So if they are mutable, you're in trouble! For Integers, it's fine though – ACV Feb 03 '17 at 14:16
  • How to take a deep copy? – Shanika Ediriweera May 04 '19 at 07:12
  • @ShanikaEdiriweera: You'd need to have an element type that provides a way of creating a deep copy of itself. Then I'd suggest just iterating over one list, creating a deep copy and adding that to a new list... – Jon Skeet May 04 '19 at 07:44
  • @JonSkeet Isn't there an easy way using java8 streams? – Shanika Ediriweera May 04 '19 at 08:10
  • 1
    @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. – Jon Skeet May 04 '19 at 08:21
  • Why this is not a deep copy? `new ArrayList<>(oldList)` creates a new ArrayList. Later update on oldList will not affect this newList. – Zhou Haibo Jul 20 '21 at 16:49
  • @ChuckZHB: It takes a shallow copy of the list, in that if the list contains references to mutable objects, then it's *only* copying those references. A deep copy would clone each object. – Jon Skeet Jul 20 '21 at 17:50
  • @JonSkeet, thanks. I usually do this sort of `new ArrayList<>(oldList)` when dealing with backtracking algorithms like `permutation` in case I would not change the newList when I change the old one as that ArrayList is a reference, and I think it is a deep copy. But now I need to take a re-look, maybe my understanding is completely wrong. – Zhou Haibo Jul 21 '21 at 03:57
  • Thank you so much. I've just wasted 6 hours trying to sort a bug in my code because I didn't know that ArrayList cannot just be assigned to another object. – ibyte Feb 08 '23 at 15:49
74

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

martijnn2008
  • 3,552
  • 5
  • 30
  • 40
Sergii Zagriichuk
  • 5,389
  • 5
  • 28
  • 45
  • 16
    Care to explain why this might be preferable to `new ArrayList<>(source);`? – Alex Jan 04 '16 at 12:00
  • 8
    @atc it's one more way to do shallow copy, instead of new ArrayList() it's used another algorithm and can be used for any List implementation, not just for an ArrayList, that is all :) – Sergii Zagriichuk Jan 04 '16 at 20:21
  • 20
    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 – ACV Feb 03 '17 at 14:18
  • 7
    nowhere in java-api deep cloning is done by any collection class – Vikash May 05 '18 at 15:46
  • 4
    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.](http://hg.openjdk.java.net/jdk8/jdk8/jdk/file/687fd7c7986d/src/share/classes/java/util/Collections.java#l596) – Radiodef Aug 03 '18 at 16:49
  • This method doesn't work. If you need to create a copy then use new ArrayList<>(oldList); – 4aRk Kn1gh7 Jan 06 '22 at 12:42
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.

Ruslan Ostafiichuk
  • 4,422
  • 6
  • 30
  • 35
Alfredo Osorio
  • 11,297
  • 12
  • 56
  • 84
  • Can you please explain the difference between `List l2 = new ArrayList(l1)` and `List l2 = l1`? – MortalMan Oct 18 '15 at 20:30
  • @MortalMan the difference is that l2 = new ArrayList(l1) is an entirely new object and modifying l2 doesn't affect l1, whereas List 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. – Alfredo Osorio Oct 19 '15 at 00:33
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.

Harshal Waghmare
  • 1,944
  • 2
  • 20
  • 21
  • 12
    i'm not entirely sure this is accurate. my test shows the opposite (still referencing same object) – invertigo Sep 19 '13 at 20:33
  • this solution worked for me when using ArrayList with ArrayAdapter – albanx Jun 26 '16 at 18:14
  • 2
    This answer is wrong. addAll() just copies the references as invertigo said. This is not a deep copy. – jk7 Feb 28 '18 at 18:08
  • For an ArrayList this answer is acceptable because String is immutable, but try it with the OP's example, an ArraList, and you'll see it is just copying references. – jk7 Feb 28 '18 at 18:43
  • 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 and ArrayList. Where it fails is for complex objects that are not immutable. – jk7 Feb 28 '18 at 23:02
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);

vaibhav agrawal
  • 111
  • 1
  • 3
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.

JB Nizet
  • 678,734
  • 91
  • 1,224
  • 1,255
1

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.

Community
  • 1
  • 1
Basil Bourque
  • 303,325
  • 100
  • 852
  • 1,154
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()));
Florian D.
  • 250
  • 3
  • 9
1

1 :you can use addAll()

newList.addAll(oldList);

2 : you can copy new arraylist if you create!

ArrayList<String> newList = new ArrayList<>(OldList);
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