1. 程式人生 > >Thinking in java自讀筆記:傳遞物件與克隆

Thinking in java自讀筆記:傳遞物件與克隆

前提:對於常規資料型別而言,可以分為值型別和引用型別,值型別為我們常說的”主型別”,”值型別”直接將記憶體儲存在棧內,由系統自動釋放資源的資料型別;引用型別是由型別的實際值引用(類似於指標)表示的資料型別,即一個在棧上的引用指向一個在堆上的例項的型別。

一.值的傳遞

當將應用型別和值型別作為引數進行傳遞時,會製作一個本地副本(引用型別我認為也是有一個副本,只不過是引用的副本),以下為2種情形:
1.值型別傳遞
public void f(int b);
這裡寫圖片描述
因此值型別傳值在方法體內對b的操作不會影響到a的值
2.引用型別傳遞
public void f(Object b)
這裡寫圖片描述


因此引用型別傳值在方法體內對b的操作會影響到a的值,但只能改變值,不能改變引用關係,如b=null,這時a並不等於null,這個操作只是將b指向空,a依舊指向a的例項。

二.物件的克隆

物件要具備克隆能力,必須實現Cloneable介面,這個介面不含任何方法,它只是一個標識,表明這個型別的物件具備克隆能力,在具備克隆能力之後,還得重寫clone()方法,將之覆蓋為public。物件的克隆分為“淺層次克隆”於”深層次克隆”。以下為普通物件和合成物件的測試。
1.普通物件的克隆

public class Test {
    public static void main(String[] args) throws  CloneNotSupportedException{
        Student a=new
Student("Lz"); Student b=a.clone(); b.name="Qy"; System.out.println(a.hashCode()+a.name); System.out.println(b.hashCode()+b.name); } } class Student implements Cloneable { String name; Student(String name) { this.name=name; } @Override public
Student clone() throws CloneNotSupportedException { Student o=null; o=(Student) super.clone(); return o; } }

這是最簡單的克隆情況,輸出2個物件的名字和hashCode(),發現名字和hashCode()都是不一樣,這是2個不同的物件。
2.合成物件的“淺層次”克隆

public class Test {
    public static void main(String[] args) throws  CloneNotSupportedException{
        MyClass classOne=new MyClass();
        MyClass classTwo=classOne.clone();
        System.out.println(classOne.hashCode());
        System.out.println(classTwo.hashCode());

        classOne.a.name="QE";
        System.out.println(classTwo.a.name);

        System.out.println(classOne.a.hashCode());
        System.out.println(classTwo.a.hashCode());
    }
}
class MyClass implements Cloneable
{
    Student a=new Student("Lz");
    Student b=new Student("Qy");

    @Override
    public MyClass clone() throws CloneNotSupportedException {
        MyClass o=null;
        o=(MyClass) super.clone();
        return o;
    }
}
class Student implements Cloneable
{
    String name;
    Student(String name)
    {
        this.name=name;
    }

    @Override
    public Student clone() throws CloneNotSupportedException {
        Student o=null;
        o=(Student) super.clone();
        return o;
    }
}

輸出結果:
這裡寫圖片描述
從結果中,可以發現classOne和classTwo是2個不同的物件,它們的hashCode()不同,改變classOne.a.name的值,classTwo.a.name的值也跟著改變,且它們的hashCode()相同,它們是同一個物件。這是為什麼呢?這就是”淺層次複製”,即只複製了物件的表面,它的內部物件並沒有改變。
3.合成物件的“深層次克隆”
將Myclass類的clone()方法改成下面這樣:

    @Override
    public MyClass clone() throws CloneNotSupportedException {
        MyClass o=null;
        o=(MyClass) super.clone();
        o.a=a.clone();
        o.b=b.clone();
        return o;
    }

在clone()裡面,手動呼叫內部物件的克隆方法,將表面物件的內部物件引用分別指向內部物件clone()方法返回的物件。