JAVA引用傳遞、淺拷貝、深拷貝

測試類:

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接口,序列化,寫入文件再讀出,這個很好理解,讀出來,是一個新的實例了,肯定是深拷貝。不再贅述。

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