178

I have an ArrayList<String> that I'd like to return a copy of. ArrayList has a clone method which has the following signature:

public Object clone()

After I call this method, how do I cast the returned Object back to ArrayList<String>?

Bill the Lizard
  • 398,270
  • 210
  • 566
  • 880
  • 17
    No, this is a valid question. Java does not support "true" generics, with runtime type erasure and all, so these kinds of details can be tricky. Furthermore, the Cloneable interface and the Object.clone() method mechanism is similarly confusing. – Tim Frey Sep 10 '08 at 18:19
  • 1
    OK, I mostly do C# where this is really easy. Please let me know if you want me to remove the comments from this question. – Espo Sep 10 '08 at 18:21
  • 1
    You can leave the comment. I think my edits explained what I was having trouble with. – Bill the Lizard Sep 10 '08 at 18:23
  • 2
    Your comment is OK, if a bit condescending. I imagine a lot of hoops that Java developers have to jump through seem silly to .NET developers. – Tim Frey Sep 10 '08 at 18:24
  • Uh?... What was the problem again? I didn't quite get it. The question was "How to invoke clone on List interface?" I think problem is the same for generic or not generic lists. Was that the question? or am I missing something here? – OscarRyz Dec 08 '08 at 18:28
  • 1
    @Oscar, he wants to clone, and not to invoke the clone command. It may not be the same it the clone doesn't really clones. I think this is the point. This is indeed a tricky question. – Rafa Mar 04 '13 at 12:54
  • @BilltheLizard Do you prefer the 30(ish) upvote answer or have you just not revisited it since the 180(ish) answer was posted? – Jasper Dec 09 '15 at 14:40

14 Answers14

349

Why would you want to clone? Creating a new list usually makes more sense.

List<String> strs;
...
List<String> newStrs = new ArrayList<>(strs);

Job done.

Tom Hawtin - tackline
  • 145,806
  • 30
  • 211
  • 305
65
ArrayList newArrayList = (ArrayList) oldArrayList.clone();
Vinko Vrsalovic
  • 330,807
  • 53
  • 334
  • 373
  • 45
    This will work fine for Strings (which is what the question asked for), but it is worth noting that ArrayList.clone will perform a shallow copy, so if there were mutable objects in the list, they will not be cloned (and changing one in one list will change that one in the other list as well. – pkaeding Sep 10 '08 at 18:25
  • 51
    You should avoid using raw types in anything but legacy code. You're better off using `ArrayList newArrayList = (ArrayList) oldArrayList.clone();`. – cdmckay Mar 01 '09 at 03:34
  • 21
    It's too bad ArrayList has a #clone method, but List itself doesn't. Sigh. – rogerdpack Sep 24 '12 at 15:50
  • 12
    Not related but while at it: use `List` instead of `ArrayList` on the left-hand side. This is how collections should be used most of the time. – Christophe Roussy Jan 28 '13 at 14:05
  • 3
    I could not use this method to duplicate an ArrayList. The clone() method was not recognized. – Jack May 13 '14 at 10:44
  • 1
    @Jack, the mistake in your case is that you try to call clone() method via List interface, not via ArrayList class. – JRr May 17 '16 at 10:30
19

This is the code I use for that:

ArrayList copy = new ArrayList (original.size());
Collections.copy(copy, original);

Hope is usefull for you

Aracem
  • 7,227
  • 4
  • 35
  • 72
GeRmAn
  • 231
  • 2
  • 2
19

With Java 8 it can be cloned with a stream.

import static java.util.stream.Collectors.toList;

...

List<AnObject> clone = myList.stream().collect(toList());
Simon Jenkins
  • 688
  • 8
  • 11
  • Can be done like List xy = new ArrayList<>(oldList); – mirzak Apr 25 '18 at 09:30
  • 2
    This is not a deep copy, changes on one list's elements can be seen in another – Inchara Jul 12 '18 at 18:28
  • 3
    Where in the question does it specify a deep copy is required? The assumption is that another collection containing the same objects is required. If you want to go down the deep copy route then you are opening up a whole new can of worms. – Simon Jenkins Jul 26 '18 at 10:52
  • Not really a clone though, is it? From the API docs "There are no guarantees on the type, mutability, serializability, or thread-safety of the List returned". Euw, don't want one of those. `toCollection` may be a better choice. – Tom Hawtin - tackline Jul 26 '19 at 22:11
  • Why has this answer so many upvotes?! Question clearly asks for a clone, i.e. a deep copy, please downvote this answer! – jan Sep 23 '21 at 07:55
17

Be advised that Object.clone() has some major problems, and its use is discouraged in most cases. Please see Item 11, from "Effective Java" by Joshua Bloch for a complete answer. I believe you can safely use Object.clone() on primitive type arrays, but apart from that you need to be judicious about properly using and overriding clone. You are probably better off defining a copy constructor or a static factory method that explicitly clones the object according to your semantics.

Julien Chastang
  • 17,592
  • 12
  • 63
  • 89
15

I think this should do the trick using the Collections API:

Note: the copy method runs in linear time.

//assume oldList exists and has data in it.
List<String> newList = new ArrayList<String>();
Collections.copy(newList, oldList);
Aaron
  • 23,450
  • 10
  • 49
  • 48
  • 13
    Why not just use new ArrayList(oldList) ? – cdmckay Mar 01 '09 at 03:33
  • 4
    I believe this wouldn't work, from doc * The destination list must be at least as long as the source list. If it is longer, the remaining elements in the destination list are unaffected. – Greg Domjan Jul 26 '12 at 15:54
  • @GregDomjan not that i agree that this is the best way, but it's a way to do it. To get around your issue it's as simeple as this: List newList = new ArrayList<>(oldList.size()); – nckbrz Jun 18 '14 at 05:43
  • 1
    Not sure if it's related to Java 8, but even when specifying the size, still getting an exception *IndexOutOfBoundsException: destination.size() < source.size(): 0 < 2* on `List copyList = new ArrayList<>(mMySerializableObjects.size());` It seems using `copyList.addAll(original);` is a good alternative – Gene Bo Nov 21 '16 at 20:51
  • @GeneBo It isn't specifying the size. It's specifying the capacity, which is a very different thing. The joy of mystery `int` arguments. I've no idea why you want to use this obscure static method instead of good old `addAll`. – Tom Hawtin - tackline Jul 15 '20 at 21:10
12

I find using addAll works fine.

ArrayList<String> copy = new ArrayList<String>();
copy.addAll(original);

parentheses are used rather than the generics syntax

Jonathan Precise
  • 327
  • 3
  • 12
Allain Lalonde
  • 91,574
  • 70
  • 187
  • 238
  • 7
    That'll work for Strings, but not for mutable objects. You'll want to clone those as well. – jodonnell Sep 10 '08 at 18:16
  • Yeah, his question is for strings. And he has the problem of generics which don't really like the casting stuff in this case. – Allain Lalonde Sep 10 '08 at 18:17
  • Also, ArrayList.clone will only do a shallow clone, so mutable objects in the list won't be cloned using that method either. – pkaeding Sep 10 '08 at 18:23
  • That should be ArrayList btw. Also, you're probably better off using new ArrayList(original) as it's less writing and just as clear. – cdmckay Mar 01 '09 at 03:32
  • 4
    Why not just use `new ArrayList(original)` ? – user102008 Jul 06 '11 at 06:49
  • Looking at the OpenJDK 8 source code, using `List copy = new ArrayList<>(original);` has the added benefit of less overhead and might be a tiiiny bit quicker compared to `List list = new ArrayList<>(original); list.addAll(orig);` (haven't tested, although using constructor arguments instead of `addAll(Collection)` just for the performance benefit delves into the premature optimization territory, I just use it because it's shorter tbh) – Jonathan Precise Jul 01 '18 at 13:37
8
List<String> shallowClonedList = new ArrayList<>(listOfStrings);

Keep in mind that this is only a shallow not a deep copy, ie. you get a new list, but the entries are the same. This is no problem for simply strings. Get's more tricky when the list entries are objects themself.

Robert
  • 1,579
  • 1
  • 21
  • 36
7

If you want this in order to be able to return the List in a getter it would be better to do:

ImmutableList.copyOf(list);
Uri Shalit
  • 2,198
  • 2
  • 19
  • 29
4

To clone a generic interface like java.util.List you will just need to cast it. here you are an example:

List list = new ArrayList();
List list2 = ((List) ( (ArrayList) list).clone());

It is a bit tricky, but it works, if you are limited to return a List interface, so anyone after you can implement your list whenever he wants.

I know this answer is close to the final answer, but my answer answers how to do all of that while you are working with List -the generic parent- not ArrayList

Ahmed Hamdy
  • 2,547
  • 1
  • 17
  • 23
3

Be very careful when cloning ArrayLists. Cloning in java is shallow. This means that it will only clone the Arraylist itself and not its members. So if you have an ArrayList X1 and clone it into X2 any change in X2 will also manifest in X1 and vice-versa. When you clone you will only generate a new ArrayList with pointers to the same elements in the original.

Juan Besa
  • 4,401
  • 5
  • 24
  • 25
2

This should also work:

ArrayList<String> orig = new ArrayList<String>();
ArrayList<String> copy = (ArrayList<String>) orig.clone()
user2627846
  • 413
  • 4
  • 17
pkaeding
  • 36,513
  • 30
  • 103
  • 141
1
ArrayList first = new ArrayList ();
ArrayList copy = (ArrayList) first.clone ();
jodonnell
  • 49,859
  • 10
  • 62
  • 67
1

I am not a java professional, but I have the same problem and I tried to solve by this method. (It suppose that T has a copy constructor).

 public static <T extends Object> List<T> clone(List<T> list) {
      try {
           List<T> c = list.getClass().newInstance();
           for(T t: list) {
             T copy = (T) t.getClass().getDeclaredConstructor(t.getclass()).newInstance(t);
             c.add(copy);
           }
           return c;
      } catch(Exception e) {
           throw new RuntimeException("List cloning unsupported",e);
      }
}
Petr
  • 1,159
  • 10
  • 20
  • There's no guarantee that the `List` implementation class has a public no-arg constructor. For instance, the `List`s returns by `Array.asList`, `List.of` or `List.subList` probably don't. – Tom Hawtin - tackline Jul 15 '20 at 21:13