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()方法返回的物件。