最近在刷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