Java 浅拷贝和深拷贝的理解和实现方式

来源:互联网 发布:php 取字符串前几位 编辑:程序博客网 时间:2024/05/22 07:50

Java中的对象拷贝(Object Copy)指的是将一个对象的所有属性(成员变量)拷贝到另一个有着相同类类型的对象中去。举例说明:比如,对象A和对象B都属于类S,具有属性a和b。那么对对象A进行拷贝操作赋值给对象B就是:B.a=A.a;  B.b=A.b;

在程序中拷贝对象是很常见的,主要是为了在新的上下文环境中复用现有对象的部分或全部 数据。

Java中的对象拷贝主要分为:浅拷贝(Shallow Copy)、深拷贝(Deep Copy)。

先介绍一点铺垫知识:Java中的数据类型分为基本数据类型和引用数据类型。对于这两种数据类型,在进行赋值操作、用作方法参数或返回值时,会有值传递和引用(地址)传递的差别。

浅拷贝(Shallow Copy):①对于数据类型是基本数据类型的成员变量,浅拷贝会直接进行值传递,也就是将该属性值复制一份给新的对象。因为是两份不同的数据,所以对其中一个对象的该成员变量值进行修改,不会影响另一个对象拷贝得到的数据。②对于数据类型是引用数据类型的成员变量,比如说成员变量是某个数组、某个类的对象等,那么浅拷贝会进行引用传递,也就是只是将该成员变量的引用值(内存地址)复制一份给新的对象。因为实际上两个对象的该成员变量都指向同一个实例。在这种情况下,在一个对象中修改该成员变量会影响到另一个对象的该成员变量值。

具体模型如图所示:可以看到基本数据类型的成员变量,对其值创建了新的拷贝。而引用数据类型的成员变量的实例仍然是只有一份,两个对象的该成员变量都指向同一个实例。

 

浅拷贝的实现方式主要有三种:

一、通过拷贝构造方法就行浅拷贝:

拷贝构造方法指的是该类的构造方法参数为该类的对象。使用拷贝构造方法可以很好地完成浅拷贝,直接通过一个现有的对象创建出与该对象属性相同的新的对象。

代码参考如下:

复制代码
/* 拷贝构造方法实现浅拷贝 */public class CopyConstructor {    public static void main(String[] args) {        Person p1=new Person(20,"摇头耶稣");        Person p2=new Person(p1);        System.out.println(p2);    }}class Person{    private int age;    private String name;    public Person(int age,String name) {        this.age=age;        this.name=name;    }    public Person(Person p) {        this.name=p.name;        this.age=p.age;    }        //声明拷贝构造方法,方法体中将所有属性都进行赋值    public String toString() {        return this.name+this.age;    }}    
复制代码

运行结果为:

摇头耶稣20

要注意:拷贝构造方法有且只能实现浅拷贝!

二、通过重写clone()方法进行浅拷贝:

Object类是类结构的根类,其中有一个方法为protected Object clone() throws CloneNotSupportedException,这个方法就是进行的浅拷贝。有了这个浅拷贝模板,我们可以通过调用clone()方法来实现对象的浅拷贝。但是需要注意:1、Object类虽然有这个方法,但是这个方法是受保护的(被protected修饰),所以我们无法直接使用。2、使用clone方法的类必须实现Cloneable接口,否则会抛出异常CloneNotSupportedException。对于这两点,我们的解决方法是,在要使用clone方法的类中重写clone()方法,通过super.clone()调用Object类中的原clone方法。

参考代码如下:对Student类的对象进行拷贝,直接重写clone()方法,通过调用clone方法即可完成浅拷贝。

 

复制代码
/* clone方法实现浅拷贝 */public class ShallowCopy {    public static void main(String[] args) {        Age a=new Age(20);        Student stu1=new Student("摇头耶稣",a,175);                //通过调用重写后的clone方法进行浅拷贝        Student stu2=(Student)stu1.clone();        System.out.println(stu1.toString());        System.out.println(stu2.toString());                //尝试修改stu1中的各属性,观察stu2的属性有没有变化        stu1.setName("大傻子");        //改变age这个引用类型的成员变量的值        a.setAge(99);        //stu1.setaAge(new Age(99));    使用这种方式修改age属性值的话,stu2是不会跟着改变的。因为创建了一个新的Age类对象而不是改变原对象的实例值        stu1.setLength(216);        System.out.println(stu1.toString());        System.out.println(stu2.toString());    }}/* * 创建年龄类 */class Age{    //年龄类的成员变量(属性)    private int age;    //构造方法    public Age(int age) {        this.age=age;    }        public int getAge() {        return age;    }        public void setAge(int age) {        this.age = age;    }        public String toString() {
原创粉丝点击