最近在刷Leetcode,里面经常用到ArrayList,对于ArrayList的拷贝也是弄得不是很明白。
ArrayList的拷贝方法有很多,其中大部分都是浅拷贝,例如通过构造函数方法拷贝,
1 List<Integer> l2 = new ArrayList<>(l1);
或者addAll方法:
1 List<Integer> l2 = new ArrayList<>(); 2 l2.addAll(l1);
这些都是浅拷贝,其中clone()方式有些特殊,最开始我以为通过clone()是实现深拷贝,因为我看很多题解都是用这种方式进行拷贝。但其实clone()也是浅拷贝,原因如下:
之所以题解经常用clone()或者构造方法直接进行复制,是因为做题通常是Interger或者String类型的List,Interger和String类型都是不可变类,那么只需要通过浅拷贝拷贝一层即可。
而后,我看一些文章写深拷贝方法,其中有一个比较特殊。
例如有一个Person类如下:
static class Person implements Cloneable{ int age; public Person(int age){this.age = age;} @Override protected Object clone() throws CloneNotSupportedException { return super.clone(); } }
通过以下代码,可以实现深拷贝;
List<Person> l3 = new ArrayList<>(); List<Person> l4 = new ArrayList<>(); for (Person person:l3) l4.add((Person)person.clone());
但是这样的说法不准确,这样的代码只是多拷贝了一层,如果Person类改成如下,这样的拷贝就不成立了。
static class Person implements Cloneable{ int a; Age age; public Person(int a){this.a = a;} @Override protected Object clone() throws CloneNotSupportedException { return super.clone(); } }
虽然完成了对Person的拷贝,改变person2的属性值不会影响到person1,但是person1和person2引用的Age对象是同一个,也就是没有实现深拷贝。
后来发现,在实际场景中,在代码逻辑层面想要完全实现深拷贝非常困难,因为难免会碰到有一些类套娃套了很多层。于是经过继续看一些文章,发现使用序列化方法可以实现深拷贝。
这段代码来自其他文章
1 public static <T> List<T> deepCopy(List<T> src) throws IOException, ClassNotFoundException { 2 ByteArrayOutputStream byteOut = new ByteArrayOutputStream(); 3 ObjectOutputStream out = new ObjectOutputStream(byteOut); 4 out.writeObject(src); 5 6 ByteArrayInputStream byteIn = new ByteArrayInputStream(byteOut.toByteArray()); 7 ObjectInputStream in = new ObjectInputStream(byteIn); 8 9 List<T> copy_list = (List<T>) in.readObject(); 10 return copy_list; 11 }
所有需要拷贝到的对象,通通要实现Serializable
static class Person implements Serializable static class Age implements Serializable