[Java]ArrayList的深拷贝与浅拷贝

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

 

posted @ 2020-02-22 14:02  咕咕刘三刀  阅读(12065)  评论(2编辑  收藏  举报