2

I have two List :

List<Object> listA = new ArrayList<Object>();
List<Object> newListB = new ArrayList<Object>();

How can i copy the contents of listA into newListB such as if i change one of the elements in my copied list, i dont want to change it in my original list.

Ole V.V.
  • 81,772
  • 15
  • 137
  • 161
Younes Ouchala
  • 300
  • 1
  • 4
  • 15
  • http://stackoverflow.com/questions/15778645/passing-arraylist-as-value-only-and-not-reference – vlaxmi Mar 30 '17 at 13:31
  • 1
    its not that what i want because if i change one of the elements in my copied list, it well change also in my original list. – Younes Ouchala Mar 30 '17 at 13:33
  • @Jens this is not duplicate of that. Please remove flag. he is not asking about List to be cloned. but he wants to clone object inside the List. – Dhiraj Mar 30 '17 at 13:38
  • @Dhiraj yep its not duplicated thank you for your attention – Younes Ouchala Mar 30 '17 at 13:39
  • @Xenu i will try to help you still using comments. if he removes the flag i will give you it in answer in details. as of now just iterate the listA and clone each element and add to newListB – Dhiraj Mar 30 '17 at 13:40
  • It depends on a way to copy each object contained in the original list. Not all objects can be copied, and the way to do it varies by class. – Ole V.V. Mar 30 '17 at 13:41
  • @Dhiraj its ok jens remove the flag – Younes Ouchala Mar 30 '17 at 13:44
  • @Dhiraj the methode clone() is broken in java – Younes Ouchala Mar 30 '17 at 14:00
  • See also [How do I copy an object in Java?](http://stackoverflow.com/questions/869033/how-do-i-copy-an-object-in-java) and [Deep copy, shallow copy, clone](http://stackoverflow.com/questions/6182565/deep-copy-shallow-copy-clone). – Ole V.V. Mar 30 '17 at 14:32

4 Answers4

1

You can use concept of Java deep clone:

The basic idea is this:

You have a Java object, and you want to make a complete clone (copy) of it. By marking your classes as being Serializable, you can write them out as an object stream, then read them back in as a different object. When you read the object back in as a different object, you very quickly have a deep clone of your original object.

A Java deep clone method

Getting right to the answer, the following method will let you make a deep clone of a Java object:

/**
 * This method makes a "deep clone" of any Java object it is given.
 */
 public static Object deepClone(Object object) {
   try {
     ByteArrayOutputStream baos = new ByteArrayOutputStream();
     ObjectOutputStream oos = new ObjectOutputStream(baos);
     oos.writeObject(object);
     ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
     ObjectInputStream ois = new ObjectInputStream(bais);
     return ois.readObject();
   }
   catch (Exception e) {
     e.printStackTrace();
     return null;
   }
 }

find more details in below link:

A Java deep clone (deep copy) example

Chetan Joshi
  • 5,582
  • 4
  • 30
  • 43
1

Am afraid to tell you that clone is broken in java:

  • https://en.wikipedia.org/wiki/Clone_(Java_method)
  • http://www.javapractices.com/topic/TopicAction.do?Id=71

    so you better off need to implement your deep copy method (which will bring you a O(log n) problem)

    List<Point> listA = new ArrayList<>();
    listA.add(new Point(0, 0));
    listA.add(new Point(1, 1));
    listA.add(new Point(2, 2));
    
    List<Point> newListB = new ArrayList<>();
    
    for (Point point : listA) {
        newListB.add(new Point(point));
    }
    System.out.println("Before deep copy");
    System.out.println(listA);
    System.out.println(newListB);
    listA.get(0).setX(987);
    listA.get(0).setY(987);
    System.out.println("after changes ");
    System.out.println(listA);
    System.out.println(newListB);
    
ΦXocę 웃 Пepeúpa ツ
  • 47,427
  • 17
  • 69
  • 97
1
Just use the constructor public ArrayList(Collection c) to construct your second list by passing the first. It initializes your list with all the items in your first list in the order given by your iterator.

You can use Reflection to deep copy all the elements of one list to another. See the example code below which can be extended to cover your needs, more (deeper) cases etc.

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;

public class Main {

    public static void main(String[] args) {

        List<Object> listA = new ArrayList<>();

        listA.add(false);
        listA.add(123);
        listA.add("test");
        listA.add(new Foo(1, "foo", 7, new Bar(2)));

        System.out.println("==ListA==");
        listA.forEach(x -> System.out.println(x));

        List<Object> listB = new ArrayList<>(listA.size());

        for (Object obj : listA) {
            try {
                Object o = null;
                if (isPrimitiveWrapperClassOrString(obj.getClass())) {
                    o = newInstance(obj);
                } else {
                    o = obj.getClass().newInstance();
                    copyValues(obj, o);
                }
                listB.add(o);
            } catch (NoSuchMethodException e) {
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            } catch (InstantiationException e) {
                e.printStackTrace();
            } catch (InvocationTargetException e) {
                e.printStackTrace();
            }
        }

        System.out.println("\n==ListB==");
        listB.forEach(x -> System.out.println(x));

        // Modify listB
        listB.set(0, true);
        listB.set(1, 456);
        ((Foo)listB.get(3)).setId(2);
        ((Bar)((Foo)listB.get(3)).getBar()).setId(9);

        System.out.println("\n==ListA after modifying listB==");
        listA.forEach(x -> System.out.println(x));

        System.out.println("\n==ListB==");
        listB.forEach(x -> System.out.println(x));
    }

    private static Object newInstance(Object obj) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
        Class classType = obj.getClass();
        Object o = null;

        if (classType == Boolean.class) {
            Method method = classType.getDeclaredMethod("booleanValue", null);
            boolean value = (boolean) method.invoke(obj, null);
            o = classType.getConstructor(boolean.class).newInstance(value);
        } else if (classType == Byte.class) {
            Method method = classType.getDeclaredMethod("byteValue", null);
            byte value = (byte) method.invoke(obj, null);
            o = classType.getConstructor(byte.class).newInstance(value);
        } else if (classType == Short.class) {
            Method method = classType.getDeclaredMethod("shortValue", null);
            short value = (short) method.invoke(obj, null);
            o = classType.getConstructor(short.class).newInstance(value);
        } else if (classType == Integer.class) {
            Method method = classType.getDeclaredMethod("intValue", null);
            int value = (int) method.invoke(obj, null);
            o = classType.getConstructor(int.class).newInstance(value);
        } else if (classType == Long.class) {
            Method method = classType.getDeclaredMethod("longValue", null);
            long value = (long) method.invoke(obj, null);
            o = classType.getConstructor(long.class).newInstance(value);
        } else if (classType == Float.class) {
            Method method = classType.getDeclaredMethod("floatValue", null);
            float value = (float) method.invoke(obj, null);
            o = classType.getConstructor(float.class).newInstance(value);
        } else if (classType == Double.class) {
            Method method = classType.getDeclaredMethod("doubleValue", null);
            double value = (double) method.invoke(obj, null);
            o = classType.getConstructor(double.class).newInstance(value);
        } else if (classType == Character.class) {
            Method method = classType.getDeclaredMethod("charValue", null);
            char value = (char) method.invoke(obj, null);
            o = classType.getConstructor(char.class).newInstance(value);
        } else if (classType == String.class) {
            Method method = classType.getDeclaredMethod("toString", null);
            String value = (String) method.invoke(obj, null);
            o = classType.getConstructor(String.class).newInstance(value);
        }

        return o;
    }

    private static void copyValues(Object objF, Object objT) throws IllegalAccessException, InstantiationException {
        Class classType = objF.getClass();
        for (Field field : classType.getDeclaredFields()) {
            field.setAccessible(true);
            Class fieldType = field.getType();
            if (isPrimitiveWrapperClassOrString(fieldType)) {
                field.set(objT, field.get(objF));
            } else {
                Object objN = field.get(objT);
                if (Objects.isNull(objN)) objN = field.getType().newInstance();
                copyValues(field.get(objF), objN);
                field.set(objT, objN);
            }
        }
    }

    private static boolean isPrimitiveWrapperClassOrString(Class classType) {
        return classType == Boolean.class || classType == boolean.class ||
                classType == Byte.class || classType == byte.class ||
                classType == Short.class || classType == short.class ||
                classType == Integer.class || classType == int.class ||
                classType == Long.class || classType == long.class ||
                classType == Float.class || classType == float.class ||
                classType == Double.class || classType == double.class ||
                classType == Character.class || classType == char.class ||
                classType == String.class;
    }
}

class Foo {
    private int id;
    private String label;
    private Integer stock;
    private Bar bar;

    public Foo() { }
    public Foo(int id, String label, Integer stock, Bar bar) {
        this.id = id;
        this.label = label;
        this.stock = stock;
        this.bar = bar;
    }

    public int getId() { return this.id; }
    public void setId(int id) { this.id = id; }
    public String getLabel() { return this.label; }
    public void setLabel() { this.label = label; }
    public Integer getStock() { return this.stock; }
    public void setStock(Integer stock) { this.stock = stock; }
    public Bar getBar() { return this.bar; }
    public void setBar(Bar bar) { this.bar = bar; }

    @Override
    public String toString() {
        return String.format("%s | %d | %d | %s", this.label, this.id, this.stock, this.bar);
    }
}

class Bar {
    private int id;

    public Bar() {}
    public Bar(int id) { this.id = id; }

    public int getId() { return this.id; }
    public void setId(int id) { this.id = id; }

    @Override
    public String toString() { return "Bar: " + this.id; }
}

Which outputs

==ListA==
false
123
test
foo | 1 | 7 | Bar: 2

==ListB==
false
123
test
foo | 1 | 7 | Bar: 2

==ListA after modifying listB==
false
123
test
foo | 1 | 7 | Bar: 2

==ListB==
true
456
test
foo | 2 | 7 | Bar: 9
no_name
  • 174
  • 1
  • 5
0

Try something like this.

 List<Object> listA = new ArrayList<Object>();
    List<Object > newListB = new ArrayList<Object>();

    for (Object object : listA ) {
      newListB .add(object .clone());
    }

working example of same is as below

public static void main(String[] args){
        TestClass test = new TestClass(1);
        List<TestClass> listA = new ArrayList<TestClass>();
        listA.add(test);
            List<TestClass> newListB = new ArrayList<TestClass>();

            for (TestClass test1: listA ) {
                TestClass classSome = new TestClass();
                classSome = (TestClass)test1.clone();
              newListB.add(classSome );
            }

        System.out.println("listA id ="+listA.get(0).id);
        System.out.println("newListB id ="+newListB .get(0).id);

        newListB .get(0).setId(15);

        System.out.println("listA id ="+listA.get(0).id);
        System.out.println("newListB id ="+newListB .get(0).id);
    }

And TestClass will be as below

class TestClass implements Cloneable{
        int id;
        public TestClass(){

        }
        public TestClass(int id){
            this.id = id;   
        }

        public int getId(){
            return this.id;
        }

        public void setId(int id){
             this.id=id;
        }

        @Override
         public Object clone() {
                try {
                     return (TestClass)super.clone();
                 }
                 catch (CloneNotSupportedException e) {
                 return null;
                    // This should never happen
                 }
            }
    }
Dhiraj
  • 1,430
  • 11
  • 21
  • 1
    The idea is fine provided the objects are cloneable, but you need to cast each object to `Cloneable` before cloning. – Ole V.V. Mar 30 '17 at 13:48
  • 2
    @OleV.V. No, you don't. You don't need to cast anything. You need to *implement* `Cloneable` and follow its rather complicated rules. It would be much better to write a copy constructor. – RealSkeptic Mar 30 '17 at 13:51
  • The methode clone() is broken in java – Younes Ouchala Mar 30 '17 at 13:54
  • That work but im certainly no fan to use clone() because its broken in java – Younes Ouchala Mar 30 '17 at 14:20
  • 1
    its a java api. you may create your own way to do this. But if you implement something other way to do this. please provide that in answer to this question. – Dhiraj Mar 30 '17 at 14:35
  • @OleV.V. Still, no need to cast, and casting won't do any good because **`clone` is not in the `Cloneable` interface**. It's one of the many reason that using `clone` is considered a bad practice. For this reason, a copy constructor will require the same amount of work and you'll need to test and cast to the appropriate type anyway. – RealSkeptic Mar 30 '17 at 16:31
  • Correct, casting to `Cloneable` is nor enough, one would need to cast to a specific type in which the `clone` method is public. @RealSkeptic – Ole V.V. Mar 30 '17 at 18:42
  • The first code snippet cannot be compiled. I get “The method clone() from the type Object is not visible”. Whether you use cloning or a copy constructor, it will get complicated if the list may contain many types of objects, and impossible if you don’t know in advance what those types are. – Ole V.V. Mar 31 '17 at 09:07
  • 1
    @OleV.V. First snippet was just the example. But i have given two more snippet which is actual implemetation of this. My answer is more specific to List is having fixed type of objects. For list of object having different type ,i haven't thought about it yet. I am also curious for how to apply this for generic List . – Dhiraj Mar 31 '17 at 09:32