當我們想複製一個簡單類型的數據時:
int a=5;
int b=a;
其他7種簡單類型的複製也可以通過這種方式進行。
但當我們想複製一個對象時,就沒有這麼簡單了,
有些初學者複製對象時應該會採用如下方法:
public class Test {
public static void main(String[] args) {
Student s1=new Student();
s1.setStuId(1);
s1.setStuName("caojie");
Student s2=s1;
System.out.println(s1);
System.out.println(s2);
}
}
class Student{
private int stuId;
private String stuName;
public int getStuId() {
return stuId;
}
public void setStuId(int stuId) {
this.stuId = stuId;
}
public String getStuName() {
return stuName;
}
public void setStuName(String stuName) {
this.stuName = stuName;
}
@Override
public String toString() {
return "Student [stuId=" + stuId + ", stuName=" + stuName + "]";
}
}
如果這樣的話,當你改變s2的值得時候,s1的值也會跟着改變,這是因爲s2=s1這句話是將s1的引用賦給了s2,兩個引用指向同一個內存單元,所以改變其中一個的值,兩個對象的值都會發生改變。
那怎樣對一個對象進行有效的複製呢?
Object類有一個clone方法,protected native Object clone() throws CloneNotSupportedException,
每個類的直接父類或間接父類都是Object,所以每個類都有clone方法,但這個方法是protected的,類外不能訪問,所以每個類必須重寫clone方法進行對象的複製。
淺複製:一般 步驟
1.被複制的類需要實現cloneable接口(不實現會拋CloneNotSupportedException異常,該接口是個標記接口,不含任何方法)
2.重寫clone方法(將訪問修飾符改成public,調用super.clone獲得需要的複製對象)
修改後的代碼是這樣的:
class Student implements Cloneable{
private int stuId;
private String stuName;
public int getStuId() {
return stuId;
}
public void setStuId(int stuId) {
this.stuId = stuId;
}
public String getStuName() {
return stuName;
}
public void setStuName(String stuName) {
this.stuName = stuName;
}
@Override
protected Object clone() throws CloneNotSupportedException {
Student s1=null;
try{
s1=(Student)super.clone();//調用super.clone獲得需要複製的對象
}catch (CloneNotSupportedException e) {
e.printStackTrace();
}
return s1;
}
@Override
public String toString() {
return "Student [stuId=" + stuId + ", stuName=" + stuName + "]";
}
}
public class Test {
public static void main(String[] args) throws CloneNotSupportedException {
Student s1=new Student();
s1.setStuId(1);
s1.setStuName("caojie");
Student s2=(Student)s1.clone();
System.out.println(s1);
System.out.println(s2);
s2.setStuId(2);
System.out.println(s1);
System.out.println(s2);
}
}
打印結果:
Student [stuId=1, stuName=caojie]
Student [stuId=1, stuName=caojie]
Student [stuId=1, stuName=caojie]
Student [stuId=2, stuName=caojie]
打印System.out.println(s1==s2);輸出結果爲false
深複製
當我們在Studennt類中加入另一個類的引用,代碼如下:
class Student implements Cloneable{
private int stuId;
private String stuName;
private Address addr;
public Address getAddr() {
return addr;
}
public void setAddr(Address addr) {
this.addr = addr;
}
public int getStuId() {
return stuId;
}
public void setStuId(int stuId) {
this.stuId = stuId;
}
public String getStuName() {
return stuName;
}
public void setStuName(String stuName) {
this.stuName = stuName;
}
@Override
protected Object clone() throws CloneNotSupportedException {
Student s1=null;
try{
s1=(Student)super.clone();//調用super.clone獲得需要複製的對象
}catch (CloneNotSupportedException e) {
e.printStackTrace();
}
return s1;
}
@Override
public String toString() {
return "Student [stuId=" + stuId + ", stuName=" + stuName + ", addr=" + addr + "]";
}
}
class Address{
private String addr;
public String getAddr() {
return addr;
}
public void setAddr(String addr) {
this.addr = addr;
}
@Override
public String toString() {
return "Address [addr=" + addr + "]";
}
}
public class Test {
public static void main(String[] args) throws CloneNotSupportedException {
Address addr=new Address();
addr.setAddr("beijjj");
Student s1=new Student();
s1.setStuId(1);
s1.setStuName("caojie");
s1.setAddr(addr);
Student s2=(Student)s1.clone();
System.out.println(s1);
System.out.println(s2);
addr.setAddr("haha");
}
}
打印結果如下:
Student [stuId=1, stuName=caojie, addr=Address [addr=beijjj]]
Student [stuId=1, stuName=caojie, addr=Address [addr=beijjj]]
這樣看複製結果是沒有任何問題的
當我們改變重新改變地址時:s2.setAddr(addr);class Student implements Cloneable{
private int stuId;
private String stuName;
private Address addr;
public Address getAddr() {
return addr;
}
public void setAddr(Address addr) {
this.addr = addr;
}
public int getStuId() {
return stuId;
}
public void setStuId(int stuId) {
this.stuId = stuId;
}
public String getStuName() {
return stuName;
}
public void setStuName(String stuName) {
this.stuName = stuName;
}
@Override
protected Object clone() throws CloneNotSupportedException {
Student s1=null;
try{
s1=(Student)super.clone();//調用super.clone獲得需要複製的對象
}catch (CloneNotSupportedException e) {
e.printStackTrace();
}
return s1;
}
@Override
public String toString() {
return "Student [stuId=" + stuId + ", stuName=" + stuName + ", addr=" + addr + "]";
}
}
class Address{
private String addr;
public String getAddr() {
return addr;
}
public void setAddr(String addr) {
this.addr = addr;
}
@Override
public String toString() {
return "Address [addr=" + addr + "]";
}
}
public class Test {
public static void main(String[] args) throws CloneNotSupportedException {
Address addr=new Address();
addr.setAddr("beijjj");
Student s1=new Student();
s1.setStuId(1);
s1.setStuName("caojie");
s1.setAddr(addr);
Student s2=(Student)s1.clone();
System.out.println(s1);
System.out.println(s2);
addr.setAddr("haha");
s2.setAddr(addr);
System.out.println(s1);
System.out.println(s2);
}
}
打印結果如下:
Student [stuId=1, stuName=caojie, addr=Address [addr=beijjj]]
Student [stuId=1, stuName=caojie, addr=Address [addr=beijjj]]
Student [stuId=1, stuName=caojie, addr=Address [addr=haha]]
Student [stuId=1, stuName=caojie, addr=Address [addr=haha]]
可以發現,當我們改變其中一個對象的地址時,兩個對象的值都會發生改變
這是因爲淺複製只是複製了addr變量的引用,並沒有真正的開闢另一塊空間,將值複製後再將引用返回給新對象。
所以,爲了達到真正的複製對象,而不是純粹引用複製。我們需要將Address類可複製化,並且修改clone方法,完整代碼如下:
class Student implements Cloneable{
private int stuId;
private String stuName;
private Address addr;
public Address getAddr() {
return addr;
}
public void setAddr(Address addr) {
this.addr = addr;
}
public int getStuId() {
return stuId;
}
public void setStuId(int stuId) {
this.stuId = stuId;
}
public String getStuName() {
return stuName;
}
public void setStuName(String stuName) {
this.stuName = stuName;
}
@Override
protected Object clone() throws CloneNotSupportedException {
Student s1=null;
try{
s1=(Student)super.clone();//調用super.clone獲得需要複製的對象
//淺複製
}catch (CloneNotSupportedException e) {
e.printStackTrace();
}
s1.addr=(Address)addr.clone();//深複製
return s1;
}
@Override
public String toString() {
return "Student [stuId=" + stuId + ", stuName=" + stuName + ", addr=" + addr + "]";
}
}
class Address implements Cloneable{
private String addr;
public String getAddr() {
return addr;
}
public void setAddr(String addr) {
this.addr = addr;
}
@Override
public String toString() {
return "Address [addr=" + addr + "]";
}
@Override
protected Object clone() throws CloneNotSupportedException {
Address addr=null;
addr=(Address)super.clone();
return addr;
}
}
public class Test {
public static void main(String[] args) throws CloneNotSupportedException {
Address addr=new Address();
addr.setAddr("beijjj");
Student s1=new Student();
s1.setStuId(1);
s1.setStuName("caojie");
s1.setAddr(addr);
Student s2=(Student)s1.clone();
System.out.println(s1);
System.out.println(s2);
addr.setAddr("haha");
Address addr2=new Address();
addr2.setAddr("hehe");
s2.setAddr(addr2);
System.out.println(s1);
System.out.println(s2);
}
}
打印結果:
Student [stuId=1, stuName=caojie, addr=Address [addr=beijjj]]
Student [stuId=1, stuName=caojie, addr=Address [addr=beijjj]]
Student [stuId=1, stuName=caojie, addr=Address [addr=haha]]
Student [stuId=1, stuName=caojie, addr=Address [addr=hehe]]
public Object clone() {
Date d = null;
try {
d = (Date)super.clone();
if (cdate != null) {
d.cdate = (BaseCalendar.Date) cdate.clone();
}
} catch (CloneNotSupportedException e) {} // Won't happen
return d;
}