java物件的淺拷貝和深拷貝
阿新 • • 發佈:2018-12-10
淺拷貝
java的資料型別有基本資料型別(如:int、long等)和引用資料型別。例如:物件1中有屬性a(基本資料型別)和屬性b(引用資料型別),在進行淺拷貝到物件2時,屬性a複製屬性的值給物件2,這樣物件1和物件2修改屬性a時不會相互影響。屬性b則是複製一份引用(即記憶體地址)給物件2,這樣物件1修改屬性b後,物件2中的值也會改變。
一般通過Object的clone( )方法來實現淺複製,使用clone( )方法需要實現Cloneable介面。
clone( )方法的基本規則如下:
1、基本資料型別
進行值的拷貝,例如:int、long、byte等。
2、String
如果變數是String型別,則拷貝其地址引用,但是因為java中String是不變的,所以在修改的時候是新建一個String,這樣新物件指向新地址不影響舊物件的值。
3、物件
物件的拷貝是複製其引用地址,即新物件和原來物件共用一個物件例項。
package com.hs.copy; public class Age { private int age; public Age(int age) { super(); this.age = age; } /* (non-Javadoc) * @see java.lang.Object#toString() */ @Override public String toString() { return "Age [age=" + age + "]"; } /** * @return the age */ public int getAge() { return age; } /** * @param age the age to set */ public void setAge(int age) { this.age = age; } }
package com.hs.copy; public class Person implements Cloneable{ private String name; private Age age; public Person(String name, int age) { super(); this.name = name; this.age = new Age(age); } public Person clone(){ try { return (Person)super.clone(); } catch (CloneNotSupportedException e) { e.printStackTrace(); } return null; } /* (non-Javadoc) * @see java.lang.Object#toString() */ @Override public String toString() { return "Person [name=" + name + ", age=" + age.getAge() + "]"; } /** * @return the name */ public String getName() { return name; } /** * @param name the name to set */ public void setName(String name) { this.name = name; } /** * @return the age */ public Age getAge() { return age; } /** * @param age the age to set */ public void setAge(Age age) { this.age = age; } }
package com.hs.copy;
/**
* 淺拷貝
* @author Administrator
*
*/
public class ShallowCopy {
public static void main(String[] args) {
Person person1 = new Person("yang", 18);
System.out.println( "person1 : " + person1.toString() );
Person person2 = person1.clone();
System.out.println( "person2 : " + person2.toString() );
person2.setName("yyyy");
System.out.println();
System.out.println( "-----修改基本型別變數後-----");
System.out.println( "person1 : " + person1.toString() );
System.out.println( "person2 : " + person2.toString() );
person2.getAge().setAge(20);
System.out.println();
System.out.println( "-----修改引用型別變數後-----");
System.out.println( "person1 : " + person1.toString() );
System.out.println( "person2 : " + person2.toString() );
}
}
執行結果:
person1 : Person [name=yang, age=18]
person2 : Person [name=yang, age=18]
-----修改基本型別變數後-----
person1 : Person [name=yang, age=18]
person2 : Person [name=yyyy, age=18]
-----修改引用型別變數後-----
person1 : Person [name=yang, age=20]
person2 : Person [name=yyyy, age=20]
深拷貝
通過上面的學習,很容易發現淺拷貝有個缺陷,即變數是引用型別時並沒有實現值的拷貝。這時候就要用到深拷貝來實現了。如下是深拷貝的兩種實現。
一、將引用型別的變數以及變數的變數全部實現clone( )方法
該實現的缺點:當引用型別的變數很多、很深時,程式碼量很大
package com.hs.copy;
public class Age implements Cloneable{
private int age;
public Age(int age) {
super();
this.age = age;
}
/* (non-Javadoc)
* @see java.lang.Object#toString()
*/
@Override
public String toString() {
return "Age [age=" + age + "]";
}
/**
* 深拷貝-新增
*/
public Age clone(){
try {
return (Age)super.clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
return null;
}
/**
* @return the age
*/
public int getAge() {
return age;
}
/**
* @param age the age to set
*/
public void setAge(int age) {
this.age = age;
}
}
package com.hs.copy;
public class Person implements Cloneable{
private String name;
private Age age;
public Person(String name, int age) {
super();
this.name = name;
this.age = new Age(age);
}
/**
* 深拷貝
*/
public Person clone(){
try {
Person person = (Person)super.clone();
Age age = person.age.clone();
person.setAge(age);
return person;
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
return null;
}
/**
* 淺拷貝
*/
/*public Person clone(){
try {
return (Person)super.clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
return null;
}*/
/* (non-Javadoc)
* @see java.lang.Object#toString()
*/
@Override
public String toString() {
return "Person [name=" + name + ", age=" + age.getAge() + "]";
}
/**
* @return the name
*/
public String getName() {
return name;
}
/**
* @param name the name to set
*/
public void setName(String name) {
this.name = name;
}
/**
* @return the age
*/
public Age getAge() {
return age;
}
/**
* @param age the age to set
*/
public void setAge(Age age) {
this.age = age;
}
}
package com.hs.copy;
/**
* 深拷貝
* @author Administrator
*
*/
public class DeepCopy {
public static void main(String[] args) {
Person person1 = new Person("yang", 18);
System.out.println( "person1 : " + person1.toString() );
Person person2 = person1.clone();
System.out.println( "person2 : " + person2.toString() );
person2.setName("yyyy");
System.out.println();
System.out.println( "-----修改基本型別變數後-----");
System.out.println( "person1 : " + person1.toString() );
System.out.println( "person2 : " + person2.toString() );
person2.getAge().setAge(20);
System.out.println();
System.out.println( "-----修改引用型別變數後-----");
System.out.println( "person1 : " + person1.toString() );
System.out.println( "person2 : " + person2.toString() );
}
}
結果:
person1 : Person [name=yang, age=18]
person2 : Person [name=yang, age=18]
-----修改基本型別變數後-----
person1 : Person [name=yang, age=18]
person2 : Person [name=yyyy, age=18]
-----修改引用型別變數後-----
person1 : Person [name=yang, age=18]
person2 : Person [name=yyyy, age=20]
二、通過物件的序列化,再反序列化實現深拷貝
package com.hs.copy;
import java.io.Serializable;
public class AgeDeep implements Serializable{
private int age;
public AgeDeep(int age) {
super();
this.age = age;
}
/* (non-Javadoc)
* @see java.lang.Object#toString()
*/
@Override
public String toString() {
return "Age [age=" + age + "]";
}
/**
* @return the age
*/
public int getAge() {
return age;
}
/**
* @param age the age to set
*/
public void setAge(int age) {
this.age = age;
}
}
package com.hs.copy;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
public class PersonDeep implements Serializable {
private String name;
private AgeDeep age;
public PersonDeep(String name, int age) {
super();
this.name = name;
this.age = new AgeDeep(age);
}
public PersonDeep deepClone(){
ObjectOutputStream objectOutputStream = null;
ObjectInputStream objectInputStream = null;
try {
//序列化
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
objectOutputStream = new ObjectOutputStream(byteArrayOutputStream);
objectOutputStream.writeObject(this);
//反序列化
ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(byteArrayOutputStream.toByteArray());
objectInputStream = new ObjectInputStream(byteArrayInputStream);
return (PersonDeep)objectInputStream.readObject();
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}finally {
try {
if( objectOutputStream != null ){
objectOutputStream.close();
}
if( objectInputStream != null ){
objectInputStream.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
return null;
}
/* (non-Javadoc)
* @see java.lang.Object#toString()
*/
@Override
public String toString() {
return "Person [name=" + name + ", age=" + age.getAge() + "]";
}
/**
* @return the name
*/
public String getName() {
return name;
}
/**
* @param name the name to set
*/
public void setName(String name) {
this.name = name;
}
/**
* @return the age
*/
public AgeDeep getAge() {
return age;
}
/**
* @param age the age to set
*/
public void setAge(AgeDeep age) {
this.age = age;
}
}
package com.hs.copy;
/**
* 深拷貝
* @author Administrator
*
*/
public class DeepCopy {
/**
* 序列化深拷貝
* @param args
*/
public static void main(String[] args) {
PersonDeep person1 = new PersonDeep("yang", 18);
System.out.println( "person1 : " + person1.toString() );
PersonDeep person2 = person1.deepClone();
System.out.println( "person2 : " + person2.toString() );
person2.setName("yyyy");
System.out.println();
System.out.println( "-----修改基本型別變數後-----");
System.out.println( "person1 : " + person1.toString() );
System.out.println( "person2 : " + person2.toString() );
person2.getAge().setAge(20);
System.out.println();
System.out.println( "-----修改引用型別變數後-----");
System.out.println( "person1 : " + person1.toString() );
System.out.println( "person2 : " + person2.toString() );
}
}