深克隆和淺克隆相關問題

深克隆和淺克隆有什麼區別?

  • 淺克隆
    • 把原型對象中成員變量爲值的屬性複製給克隆對象
    • 把原型對象中成員變量爲引用的引用地址複製給克隆對象
      在這裏插入圖片描述
  • 深克隆
    • 把原型對象中的所有類型(無論是值還是引用類型)都複製一份給克隆對象
      在這裏插入圖片描述

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 講》

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章