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