深克隆和淺克隆有什麼區別?
- 淺克隆
- 把原型對象中成員變量爲值的屬性複製給克隆對象
- 把原型對象中成員變量爲引用的引用地址複製給克隆對象
- 深克隆
- 把原型對象中的所有類型(無論是值還是引用類型)都複製一份給克隆對象
- 把原型對象中的所有類型(無論是值還是引用類型)都複製一份給克隆對象
java.lang.Object 中對 clone() 方法的約定有哪些?
對於所有對象來說
x.clone()!=x
,因爲克隆對象與源對象不是同一個對象x.clone.getClass() == x.getClass()
,因爲克隆對象與原對象類型一致x.clone().equals(x)
,因爲equals比較的時他們的值,都是相同的
Arrays.copyOf()是實現深克隆還是淺克隆
- Arrays.copyOf()是淺克隆,只是將數組的引用地址複製給了克隆對象,如果克隆對象發生修改,原對象也會發生改變
深克隆實現方式有哪些?
-
所有的對象和對象內的引用對象都實現了克隆方法
- 複製的對象必須實現了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:德陽
- 通過構造方法實現深克隆
不調用方法複製對象,而是採用構造方法,將原對象的屬性一個一個設置進去
代碼演示:
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:德陽
- 通過JDK自帶的字節流實現深克隆
通過輸入輸出流自己實現一個工具類,較爲繁瑣,可以使用第三方寫好的工具類實現
- 使用第三方工具,以 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
}
- 使用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());
}
}