Java中的浅复制和深复制 Cloneable clone


先看一个简单案例
public class Test {
    public static void main(String args[]) {
        Student stu1 = new Student();
        stu1.number = 1;
        Student stu2 = stu1;//stu1和stu2指向堆内存中同一个对象
        System.out.println("学生1:" + stu1.number + "    学生2:" + stu2.number);
        stu2.number = 2;
        System.out.println("学生1:" + stu1.number + "    学生2:" + stu2.number);
        System.out.println(stu1 == stu2);
    }
}
class Student {
    public int number;
}
Java中的浅复制和深复制 Cloneable clone
如上这种形式,仅仅将一个对象的引用赋给另一个引用,并没有复制出另一个对象,这两个引用指向的是内存中的同一个对象
所以,这根本不叫对象的复制

对象的复制(浅复制)
public class Test {
    public static void main(String args[]) {
        Student stu1 = new Student();
        stu1.number = 1;
        Student stu2 = (Student) stu1.clone();
        System.out.println("学生1:" + stu1.number + "    学生2:" + stu2.number);
        stu2.number = 2;
        System.out.println("学生1:" + stu1.number + "    学生2:" + stu2.number);
        System.out.println(stu1 == stu2);
    }
}
class Student implements Cloneable {
    public int number;
    @Override
    public Object clone() {
        Student stu = null;
        try {
            stu = (Student) super.clone();
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }
        return stu;
    }
}
Java中的浅复制和深复制 Cloneable clone
Object有个protected的clone方法,该方法的签名是:
protected native Object clone() throws CloneNotSupportedException;
要想对一个对象进行复制,就需要覆盖clone方法,一般步骤是(浅复制):
  • 1、被复制的类需要实现Clonenable接口,不实现的话在调用clone方法会抛出CloneNotSupportedException异常,该接口为标记接口(不含任何方法)
  • 2、覆盖clone()方法,访问修饰符设为public。方法中调用super.clone()方法得到需要的复制对象(native为本地方法)

浅复制可能出现的问题
public class Test {
    public static void main(String args[]) {
        Student stu1 = new Student();
        stu1.number = 1;
        stu1.address = new Address("广州");
        stu1.courseList.add("语文");

        //复制stu1
        Student stu2 = (Student) stu1.clone();
        System.out.println("学生1:" + stu1.number + "    " + stu1.address + "    " + stu1.courseList);
        System.out.println("学生2:" + stu2.number + "    " + stu2.address + "    " + stu2.courseList);

        //更改stu2
        stu2.number = 2;
        stu2.address = new Address("深圳");
        stu2.courseList.add("数学");
        System.out.println("学生1:" + stu1.number + "    " + stu1.address + "    " + stu1.courseList);
        System.out.println("学生2:" + stu2.number + "    " + stu2.address + "    " + stu2.courseList);
    }
}
class Student implements Cloneable {
    public int number;
    public ArrayList<String> courseList = new ArrayList<String>();
    public Address address;
    @Override
    public Object clone() {
        Student stu = null;
        try {
            stu = (Student) super.clone();
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }
        return stu;
    }
}
class Address {
    public String add;
    public Address(String add) {
        this.add = add;
    }
}
Java中的浅复制和深复制 Cloneable clone
更改stu2的address和courseList后,是不是发现,stu1的相应值也变了?这是为什么呢?
这是因为Java做了一个偷懒的拷贝动作,Object类提供的方法clone只是拷贝本对象,其对象内部的数组、引用对象等都不拷贝,还是指向原生对象的内部元素的地址,这种拷贝就叫做浅拷贝。
确实是非常浅,两个对象共享了一个私有变量,你改我改大家都能改,是一个种非常不安全的方式,在实际项目中使用还是比较少的。
注意:八大基本类型和String(虽然String 是引用类型,但Java其实是希望你把它也"认为"是基本类型,String 是没有 clone 方法的)等都会被拷贝的。

深复制
public class Test {
    public static void main(String args[]) {
        Student stu1 = new Student();
        stu1.number = 1;
        stu1.address = new Address("广州");
        stu1.courseList.add("语文");
        //复制stu1
        Student stu2 = (Student) stu1.clone();
        System.out.println("学生1:" + stu1.number + "    " + stu1.address + "    " + stu1.courseList);
        System.out.println("学生2:" + stu2.number + "    " + stu2.address + "    " + stu2.courseList);
        //更改stu2
        stu2.number = 2;
        stu2.address = new Address("深圳");
        stu2.courseList.add("数学");
        System.out.println("学生1:" + stu1.number + "    " + stu1.address + "    " + stu1.courseList);
        System.out.println("学生2:" + stu2.number + "    " + stu2.address + "    " + stu2.courseList);
    }
}
class Student implements Cloneable {
    public int number;
    public ArrayList<String> courseList = new ArrayList<String>();
    public Address address;
    @SuppressWarnings("unchecked")
    @Override
    public Object clone() {
        Student stu = null;
        try {
            stu = (Student) super.clone();//浅复制 
            stu.address = (Address) address.clone(); //深度复制
            stu.courseList = (ArrayList<String>) courseList.clone();//深度复制
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }
        return stu;
    }
}
class Address implements Cloneable {//为了达到真正的复制对象,而不是纯粹引用复制。我们需要将Address类可复制化
    public String add;
    public Address(String add) {
        this.add = add;
    }
    @Override
    public Object clone() {
        Address addr = null;
        try {
            addr = (Address) super.clone();
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }
        return addr;
    }
}
Java中的浅复制和深复制 Cloneable clone

上一篇:Android动态加载jar/dex


下一篇:LeetCode_Roman to Integer