測試類:
Player類,包含name level 和 weapon 三個成員
public class Player implements Cloneable {
private static final long serialVersionUID = -75L;
private String name;
private int level;
private Weapon weapon;
public Player(){
name = "sam";
level = 10;
weapon = new Weapon();
}
public static long getSerialVersionUID() {
return serialVersionUID;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getLevel() {
return level;
}
public void setLevel(int level) {
this.level = level;
}
public Weapon getWeapon() {
return weapon;
}
public void setWeapon(Weapon weapon) {
this.weapon = weapon;
}
@Override
public String toString() {
return "Player{" +
"name='" + name + '\'' +
", level=" + level +
", weapon=" + weapon.getName() +
'}';
}
@Override
protected Object clone() throws CloneNotSupportedException {
Player o = (Player) super.clone();
return o;
}
}
Weapon:包含 name 一個成員
public class Weapon implements Cloneable {
private String name;
public Weapon(String name) {
this.name = name;
}
public Weapon() {
this.name = "AK74";
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
1. 直接賦值,引用傳遞,C2 = C1 ,不會爲複製過去的實例分配空間,C2這個引用直接指向C1的實例,C1中有成員改變,C2也同樣改變,很好理解。
這裏r1賦值給r2,之後改變r1的成員,再次打印r2
Player r1 = new Player(); Player r2 = r1; r1.setName("tom"); r1.setLevel(20); r1.getWeapon().setName("HK416"); System.out.println(r2);
輸出結果:可見r2的值已經隨着r1更新。
2. 淺拷貝,使用Object.clone()方法 ,C1複製到新實例中(堆上分配空間),C2指向這個新實例。
複製的過程中:如果字段是值類型的,那麼對該字段執行復制。如果該字段是引用類型的話,則複製引用但不復制引用的對象。
首先Player和Weapon都已實現Cloneable接口的clone方法,執行clone,之後改變r1的成員,再次打印r2內容
Player r1 = new Player(); Player r2 = (Player) r1.clone(); r1.setName("tom"); r1.setLevel(20); r1.getWeapon().setName("HK416"); System.out.println(r2);
輸出結果:r2中,字段爲值類型的部分則被複製成功,隨着r1更新,並未變化。但weapon字段卻更新爲HK416了,說明r2中的weapon還是指向了r1的weapon
3. 深拷貝,同樣使用Object.clone()方法 ,複製引用並同時複製引用的對象重構Player中的clone方法,將引用類型成員也clone過去。@Override protected Object clone() throws CloneNotSupportedException { Player o = (Player) super.clone(); o.weapon = (Weapon) weapon.clone(); return o; }
輸出結果:可見此時r2完全未受到r1成員變更的影響,通俗的理解,r2現在完全與r1脫離了。
4. 深拷貝的另一種實現:實現 Serializable接口,序列化,寫入文件再讀出,這個很好理解,讀出來,是一個新的實例了,肯定是深拷貝。不再贅述。