賦值、淺拷貝和深拷貝

NO IMAGE

直接賦值

  先定義了一個變數a,然後將a變數賦值給b。則a、b兩個變數都指向記憶體中同一個物件。

public static <T> T[] extendsArray(T[] data){
int newLength = (data.length * 3)/2   1;
return Arrays.copyOf(data, newLength);
}
public static void main(String[] args) {
TestClass[] arr = new TestClass[10];
arr[0] = new TestClass("yanjun", 24);
TestClass[] arr2 = extendsArray(arr);
arr2[0].setAge(18);
System.out.println("arr[0].age: "   arr[0].getAge());//輸出18
System.out.println("arr2[0].age: "   arr2[0].getAge());//輸出18
}

淺拷貝

  如果先定義一個a變數,然後使用clone方法拷貝一份給b變數。這實際上是建立一個新的物件給b變數,然後將a變數指向的物件的屬性賦值給b變數指向的物件。這是淺拷貝,它對於基本資料型別和String的屬性是實現了拷貝,但是對於引用型別的屬性(如本例中的cat),兩個物件是指向同一個物件。

public static void main(String[] args) {
TestClass aaa = new TestClass("yanjun", 23);
aaa.getCat().setColor("red");
aaa.getCat().setSize(23);
TestClass bbb = (TestClass) aaa.clone();
aaa.setName("new yanjun");
aaa.setAge(18);
aaa.getCat().setColor("blue");
aaa.getCat().setSize(18);
System.out.println(aaa.getName()   "--------"   bbb.getName()); //輸出new yanjun--------yanjun
System.out.println(aaa.getAge()   "--------"   bbb.getAge());//輸出18--------23
System.out.println(aaa.getCat().getColor()   "--------"   bbb.getCat().getColor());//輸出blue--------blue
System.out.println(aaa.getCat().getSize()   "--------"   bbb.getCat().getSize());//輸出18--------18
}
class TestClass implements Cloneable{
private String name;
private int age;
private Cat cat;
public TestClass(String name, int age){
this.name = name;
this.age = age;
this.cat = new Cat();
}
//省去get和set方法
public Object clone(){ 
Object o=null; 
try{ 
o=(TestClass)super.clone();//Object 中的clone()識別出你要複製的是哪一個物件。 
} 
catch(CloneNotSupportedException e){ 
System.out.println(e.toString()); 
} 
return o; 
}  
}
class Cat{
private String color;
private int size;
//省去get和set方法
public Cat() {
this.color = "red";
this.size = 23;
}
}

深拷貝

  深拷貝有兩種方式實現:層層clone的方法和利用序列化來做深拷貝

1、層層clone的方法

  在淺拷貝的基礎上實現,給引用型別的屬性新增克隆方法,並且在拷貝的時候也實現引用型別的拷貝。此種方法由於要在多個地方實現拷貝方法,可能會造成混論。

public static void main(String[] args) {
TestClass aaa = new TestClass("yanjun", 23);
aaa.getCat().setColor("red");
aaa.getCat().setSize(23);
TestClass bbb = (TestClass) aaa.clone();
aaa.setName("new yanjun");
aaa.setAge(18);
aaa.getCat().setColor("blue");
aaa.getCat().setSize(18);
System.out.println(aaa.getName()   "--------"   bbb.getName()); //輸出new yanjun--------yanjun
System.out.println(aaa.getAge()   "--------"   bbb.getAge());//輸出18--------23
System.out.println(aaa.getCat().getColor()   "--------"   bbb.getCat().getColor());//輸出blue--------red
System.out.println(aaa.getCat().getSize()   "--------"   bbb.getCat().getSize());//輸出18--------23
}
class TestClass implements Cloneable{
private String name;
private int age;
private Cat cat;
public TestClass(String name, int age){
this.name = name;
this.age = age;
this.cat = new Cat();
}
//省去get和set方法
public Object clone(){ 
TestClass o=null; 
try{ 
o=(TestClass)super.clone();//Object 中的clone()識別出你要複製的是哪一個物件。 
} 
catch(CloneNotSupportedException e){ 
System.out.println(e.toString()); 
} 
o.cat = (Cat)o.cat.clone();
return o; 
}  
}
class Cat{
private String color;
private int size;
//省去get和set方法
public Cat() {
this.color = "red";
this.size = 23;
}
public Object clone(){ 
Object o=null; 
try{ 
o=(Cat)super.clone();//Object 中的clone()識別出你要複製的是哪一個物件。 
} 
catch(CloneNotSupportedException e){ 
System.out.println(e.toString()); 
} 
return o; 
}  
}
2、利用序列化來做深拷貝

  為避免複雜物件中使用clone方法可能帶來的換亂,可以使用串化來實現深拷貝。先將物件寫到流裡,然後再重流裡讀出來。

public Object deepClone() throws IOException, ClassNotFoundException
{ 
//將物件寫到流裡 
ByteArrayOutputStream bo=new ByteArrayOutputStream(); 
ObjectOutputStream oo=new ObjectOutputStream(bo); 
oo.writeObject(this); 
//從流裡讀出來 
ByteArrayInputStream bi=new ByteArrayInputStream(bo.toByteArray()); 
ObjectInputStream oi=new ObjectInputStream(bi); 
return(oi.readObject()); 
}