深克隆和浅克隆相关问题

深克隆和浅克隆有什么区别?

  • 浅克隆
    • 把原型对象中成员变量为值的属性复制给克隆对象
    • 把原型对象中成员变量为引用的引用地址复制给克隆对象
      在这里插入图片描述
  • 深克隆
    • 把原型对象中的所有类型(无论是值还是引用类型)都复制一份给克隆对象
      在这里插入图片描述

java.lang.Object 中对 clone() 方法的约定有哪些?

对于所有对象来说

  • x.clone()!=x,因为克隆对象与源对象不是同一个对象
  • x.clone.getClass() == x.getClass(),因为克隆对象与原对象类型一致
  • x.clone().equals(x),因为equals比较的时他们的值,都是相同的

Arrays.copyOf()是实现深克隆还是浅克隆

  • Arrays.copyOf()是浅克隆,只是将数组的引用地址复制给了克隆对象,如果克隆对象发生修改,原对象也会发生改变

深克隆实现方式有哪些?

  1. 所有的对象和对象内的引用对象都实现了克隆方法

    • 复制的对象必须实现了Cloneable接口,并重写了clone方法
    • 复制的对象的属性中为引用的对象也必须重写了clone方法

代码演示
复制了一个people类,并修改了其属性对象的属性,但是原对象并没有发生修改

public class Solution {
    public static void main(String[] args) throws CloneNotSupportedException {
        Address address = new Address("中国", "成都");
        People people = new People(address, "张三");
        People people2 = people.clone();
        people2.getAddress().setCity("德阳");
        System.out.println("people:"+people.getAddress().getCity());
        System.out.println("people2:"+people2.getAddress().getCity());
    }
}

class People implements Cloneable {
    private Address address;
    private String username;

    @Override
    protected People clone() throws CloneNotSupportedException {
        People people = (People) super.clone();
        people.setAddress((Address) this.address.clone());
        return people;
    }
    //忽略构造、set、get
    
}

class Address implements Cloneable {
    private String country;
    private String city;

    @Override
    protected Address clone() throws CloneNotSupportedException {
        return (Address) super.clone();
    }
    //忽略构造、set、get
    
}

运行结果

people:成都
people2:德阳
  1. 通过构造方法实现深克隆

不调用方法复制对象,而是采用构造方法,将原对象的属性一个一个设置进去
代码演示:

public class Solution {
    public static void main(String[] args) throws CloneNotSupportedException {
        Address address = new Address("中国", "成都");
        People people = new People(address, "张三");

        People people2 = new People(
                new Address(address.getCountry(), address.getCity()),
                people.getUsername());

        people2.getAddress().setCity("德阳");

        System.out.println("people:"+people.getAddress().getCity());
        System.out.println("people2:"+people2.getAddress().getCity());
    }
}

class People {
    private Address address;
    private String username;
//忽略构造、set、get
}

class Address {
    private String country;
    private String city;
//忽略构造、set、get
}

运行结果

people:成都
people2:德阳
  1. 通过JDK自带的字节流实现深克隆

通过输入输出流自己实现一个工具类,较为繁琐,可以使用第三方写好的工具类实现

  1. 使用第三方工具,以 Apache Commons Lang为例
    • 添加相关依赖
    • 克隆对象都必须序列化,包括对象的属性引用的对象
public class Solution {
    public static void main(String[] args) throws CloneNotSupportedException {
        Address address = new Address("中国", "成都");
        People people = new People(address, "张三");

        People people2 = (People)SerializationUtils.clone(people);
        
        people2.getAddress().setCity("德阳");

        System.out.println("people:"+people.getAddress().getCity());
        System.out.println("people2:"+people2.getAddress().getCity());
    }
}


class People implements Serializable {
    private Address address;
    private String username;
//忽略构造、set、get
}

class Address implements Serializable{
    private String country;
    private String city;
//忽略构造、set、get
}
  1. 使用JSON工具类实现深克隆,如Gson,FastJSON等
public class Solution {
    public static void main(String[] args) throws CloneNotSupportedException {
        Address address = new Address("中国", "成都");
        People people = new People(address, "张三");

        Gson gson = new Gson();

        People people2 = gson.fromJson(gson.toJson(people),People.class);

        people2.getAddress().setCity("德阳");

        System.out.println("people:"+people.getAddress().getCity());
        System.out.println("people2:"+people2.getAddress().getCity());
    }
}

参考
《 Java 面试真题及源码 34 讲》

猜你喜欢

转载自blog.csdn.net/qq_41170102/article/details/105268266