android 面试题 谈谈深拷贝和浅拷贝

本文探讨了Java中的深拷贝和浅拷贝概念。浅拷贝通过Cloneable接口创建新对象,复制基本类型属性,而引用类型仍指向同一内存地址。深拷贝则对所有属性及引用对象的属性进行拷贝,创建独立的内存副本,避免对象间的相互影响。然而,深拷贝速度较慢,内存开销大,尤其当对象中包含多个引用对象时。此外,还讨论了new关键字和反射创建对象的局限性,以及如何通过序列化实现深拷贝,尽管这可能导致性能下降。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

对称拷贝就是将一个对象的属性拷贝到另一个类有着相同类类型的对象中

浅拷贝

浅拷贝就是按位拷贝对象,它会创建一个新的对象,这个对象有着原始对象属性值的一份精确拷贝,如果属性是基本类型,拷贝的就是基本类型的值,如果属性是引用类型,拷贝的就是内存地址值,因此如果其中一个对象改变了这个地址就会影响其他的对象

用demo来测试下

public class ShallowCopyTest {
    public static void main(String[] args) {
        Stu stu = new Stu("张三","Android开发");
        System.out.println("name-->"+stu.getName()+"subjectName="+stu.getSubject().getName());
        //拷贝对象
        try {
            Stu stu1 = (Stu) stu.clone();
            System.out.println("拷贝name-->"+stu1.getName());
            System.out.println("拷贝subjectName="+stu1.getSubject().getName());
            System.out.println("对比二个对象是否相等-->"+(stu==stu1));
            System.out.println("对比浅拷贝中的引用类型是否相等-->"+(stu.getSubject()==stu1.getSubject()));
            //修改原始数据中的name
            stu.setName("李四");
            System.out.println("修改原始数据name-->"+stu1.getName());
            //修改拷贝的对象中的name属性值
            stu1.setName("王五");
            System.out.println("修改拷贝后的数据name-->"+stu1.getName());
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }
    }
}
class Subject{
    private String name;

    public Subject(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}
class Stu implements Cloneable{
    private String name;
    private Subject subject;

    public Stu(String name, String subject) {
        this.name = name;
        this.subject = new Subject(subject);
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Subject getSubject() {
        return subject;
    }

    public void setSubject(Subject subject) {
        this.subject = subject;
    }

    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
}

打印结果:

name-->张三subjectName=Android开发
拷贝name-->张三
拷贝subjectName=Android开发
对比二个对象是否相等-->false
对比浅拷贝中的引用类型是否相等-->true
拷贝name-->张三
拷贝name-->王五

从中发现,修改原始数据并不影响拷贝对象中的属性 但是修改拷贝中的对象数据会影响到原始对象中的数据

实现浅拷贝的类要实现Cloneable接口,原始对象和拷贝对象不是同一个对象,其实就是要拷贝的对象中定义的属性是和原始对象一样,然后通过set方法把值赋值给拷贝对象

如果有人问你创建对象有几种方式 你可以回答 1:new. 2:反射 3:克隆

浅拷贝的弊端

当拷贝的对象中如果有引用类型,一旦这个引入类型中的属性变化了,不管是原始对象中的引用类型还是拷贝对象中的引用类型变量发生了改变,二者都会变,因为拷贝和原始对象中的引用类型在内存都是同一份,这个时候就出现了深拷贝

new关键字和反射创建对象的弊端

如果需求是要求创建出一系列相同的对象,那么使用这二者方法创建对象后每次都要通过set或者其他方式去给属性赋值,很麻烦

深拷贝

深拷贝会拷贝所有的属性,并拷贝属性指向的动态内存分配,当对象和它所引用的对象一起拷贝时即是深拷贝,深拷贝比浅拷贝的速度慢而且开销大,因为内存地址要动态创建了而不是共同一份了.

demo如下:

public class DeepCopyTest {
    public static void main(String[] args) {
        Student student = new Student("张三","Android开发");
        Person person1 = student.getPerson();
        try {
            Student student1 = student.clone();
           Person person2 =  student1.getPerson();
            System.out.println("person-name--"+person1.getName());
            System.out.println("person-name--"+person2.getName());
            //修改原始对象中的Person 对象中的那么
            person1.setName("java 开发");
            System.out.println("person-name--"+person1.getName());
            System.out.println("person-name--"+person2.getName());
            //修改拷贝后的引入对象person中的name
            person2.setName("ios 开发");
            System.out.println("person-name--"+person1.getName());
            System.out.println("person-name--"+person2.getName());

            System.out.println("----=="+(person1==person2));
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }
    }
}
class Person implements Cloneable{
    private String name;

    public Person(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @Override
    protected Person clone() throws CloneNotSupportedException {
        return (Person) super.clone();
    }
}
class Student implements Cloneable{
    private String name;
    private Person person;

    public Student(String name, String subject) {
        this.name = name;
        this.person = new Person(subject);
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Person getPerson() {
        return person;
    }

    public void setPerson(Person person) {
        this.person = person;
    }

    @Override
    public Student clone() throws CloneNotSupportedException {
        Student student =  (Student) super.clone();
        student.setPerson(person.clone());
        return student;
    }
}

深拷贝中如果有引用类型的话,这个引用对象也要实现拷贝,但它是浅拷贝,在所包含引用类型的对象中要实现深拷贝.

深拷贝的弊端

如果一个对象中有好几个引用对象的话,每个引用对象都实现Cloneable 并复写clone接口,而且所持有这个引用对象的对象也要修改clone中的方法,如果引用对象过多,对内存消耗也慢慢变大,因为深拷贝的引用对象都是要进行重新在堆内存中分配内存

上面除了使用Object中的clone来实现深拷贝,也可以使用序列化的方式来实现深拷贝,这个比较麻烦,而且这是个IO操作,性能上不高,不写demo了

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值