打开APP
userphoto
未登录

开通VIP,畅享免费电子书等14项超值服

开通VIP
是时候捋一捋 Java 的深浅拷贝了

在开发、刷题、面试中,我们可能会遇到将一个对象的属性赋值到另一个对象的情况,这种情况就叫做拷贝。拷贝与Java内存结构息息相关,搞懂Java深浅拷贝是很必要的!

在对象的拷贝中,很多初学者可能搞不清到底是拷贝了引用还是拷贝了对象。在拷贝中这里就分为引用拷贝、浅拷贝、深拷贝进行讲述。

引用拷贝

引用拷贝会生成一个新的对象引用地址,但是两个最终指向依然是同一个对象。如何更好的理解引用拷贝呢?很简单,就拿我们人来说,通常有个姓名,但是不同场合、人物对我们的叫法可能不同,但我们很清楚哪些名称都是属于"我"的!

当然,通过一个代码示例让大家领略一下(为了简便就不写get、set等方法):

class Son {

    String name;

    int age;

    public Son(String name, int age) {

        this.name = name;

        this.age = age;

    }

}public class test {

    public static void main(String[] args) {

        Son s1 = new Son("son1", 12);

        Son s2 = s1;

        s1.age = 22;

        System.out.println(s1);

        System.out.println(s2);

        System.out.println("s1的age:" + s1.age);

        System.out.println("s2的age:" + s2.age);

        System.out.println("s1==s2" + (s1 == s2));//相等

    }

}

输出的结果为:

Son@135fbaa4

Son@135fbaa4

s1的age:22

s2的age:22true

浅拷贝

如何创建一个对象,将目标对象的内容复制过来而不是直接拷贝引用呢?

这里先讲一下浅拷贝,浅拷贝会创建一个新对象,新对象和原对象本身没有任何关系,新对象和原对象不等,但是新对象的属性和老对象相同。具体可以看如下区别:

如果属性是基本类型(int,double,long,boolean等),拷贝的就是基本类型的值;

如果属性是引用类型,拷贝的就是内存地址(即复制引用但不复制引用的对象) ,因此如果其中一个对象改变了这个地址,就会影响到另一个对象。

如果用一张图来描述一下浅拷贝,

如何实现浅拷贝呢?也很简单,就是在需要拷贝的类上实现Cloneable接口并重写其clone()方法。

@Overrideprotected Object clone() throws CloneNotSupportedException {

  return super.clone();

}

在使用的时候直接调用类的clone()方法即可。具体案例如下:

class Father{

    String name;

    public Father(String name) {

        this.name=name;

    }

    @Override

    public String toString() {

        return "Father{" +

                "name='" + name + '\'' +

                '}';

    }

}class Son implements Cloneable {

    int age;

    String name;

    Father father;

    public Son(String name,int age) {

        this.age=age;

        this.name = name;

    }

    public Son(String name,int age, Father father) {

        this.age=age;

        this.name = name;

        this.father = father;

    }

    @Override

    public String toString() {

        return "Son{" +

                "age=" + age +

                ", name='" + name + '\'' +

                ", father=" + father +

                '}';

    }

    @Override

    protected Son clone() throws CloneNotSupportedException {

        return (Son) super.clone();

    }

}public class test {

    public static void main(String[] args) throws CloneNotSupportedException {

        Father f=new Father("bigFather");

        Son s1 = new Son("son1",13);

        s1.father=f;

        Son s2 = s1.clone();

        System.out.println(s1);

        System.out.println(s2);

        System.out.println("s1==s2:"+(s1 == s2));//不相等

        System.out.println("s1.name==s2.name:"+(s1.name == s2.name));//相等

        System.out.println();

        //但是他们的Father father 和String name的引用一样

        s1.age=12;

        s1.father.name="smallFather";//s1.father引用未变

        s1.name="son222";//类似 s1.name=new String("son222") 引用发生变化

        System.out.println("s1.Father==s2.Father:"+(s1.father == s2.father));//相等

        System.out.println("s1.name==s2.name:"+(s1.name == s2.name));//不相等

        System.out.println(s1);

        System.out.println(s2);

    }

}

运行结果为:

Son{age=13, name='son1', father=Father{name='bigFather'}}

Son{age=13, name='son1', father=Father{name='bigFather'}}

s1==s2:false

s1.name==s2.name:true//此时相等

s1.Father==s2.Father:true

s1.name==s2.name:false//修改引用后不等

Son{age=12, name='son222', father=Father{name='smallFather'}}

Son{age=13, name='son1', father=Father{name='smallFather'}}

不出意外,这种浅拷贝除了对象本身不同以外,各个零部件和关系和拷贝对象都是相同的,就好像双胞胎一样,是两个人,但是其开始流量交易的样貌、各种关系(父母亲人)都是相同的。需要注意的是其中name初始==是相等的,是因为初始浅拷贝它们指向一个相同的String,而后s1.name="son222" 则改变引用指向。

本站仅提供存储服务,所有内容均由用户发布,如发现有害或侵权内容,请点击举报
打开APP,阅读全文并永久保存 查看更多类似文章
猜你喜欢
类似文章
java的深拷贝
C 继承和派生
Java中数组的特性
static关键字
java笔记.equals的方法
Java中参数传递是传值还是传址?
更多类似文章 >>
生活服务
热点新闻
分享 收藏 导长图 关注 下载文章
绑定账号成功
后续可登录账号畅享VIP特权!
如果VIP功能使用有故障,
可点击这里联系客服!

联系客服