1 Java的clone方法
1.1 爲什麼需要拷貝?
在實際編程過程中,我們要遇到這種情況:有一個對象A,在某一時刻A中已經包含了一些有效值,此時可能會需要一個和A完全相同新對象B,並且此後對B任何改動都不會影響到A中的值。也就是說,A與B是兩個獨立的對象,但B的初始值是由A對象確定的。用賦值語句是不能滿足這種需求的,而通過實現clone()方法是最簡單、最高效的手段。
1.2 什麼是拷貝?
Java的所有類都默認繼承java.lang.Object類,在java.lang.Object類中有一個方法clone()。JDK API的說明文檔解釋這個方法將返回Object對象的一個拷貝。要說明的有兩點:
(1)拷貝對象返回的是一個新對象,而不是一個引用;
(2)拷貝對象與new新對象的區別就是:①這個拷貝已經包含了一些原來對象的信息,而不是對象的初始信息。 ②拷貝效率更高,因爲Object類的clone()一個native方法,native方法的效率都是遠高於非native方法。
1.2 如何使用clone()?
/**
* 一個很典型的調用clone()代碼如下
*/
public class CloneClass implements Cloneable {
public int aInt;
public Object clone() {
CloneClass o = null;
try{
o = (CloneClass)super.clone();
} catch(CloneNotSupportedException e) {
e.printStackTrace();
}
return o;
}
}
有三個值得注意的地方:
(1)希望能實現clone功能的CloneClass類實現了Cloneable接口,這個接口屬於java.lang包,java.lang包已經被缺省的導入類中;
(2)重載clone()方法;
(3)在clone()方法中調用super.clone(),指無論clone類的繼承結構是什麼樣的,super.clone()直接或間接調用了java.lang.Object類的clone()方法;
(4)爲了讓其它類能調用這個clone類的clone()方法,重載之後要把clone()方法的屬性設置爲public;
2 淺拷貝
2.1 淺拷貝是什麼?
淺拷貝:對象A複製出一個對象B來,修改對象B中的8中基本類型(包括裝箱)的值和String,對象A中不被修改。修改對象B中的引用對象,由於只拷貝其引用,對象A中的引用對象也會被修改。
2.2 例子
public class AdEntity implements Cloneable {
public String adTitle;
public AdEntity(String adTitle) {
this.adTitle = adTitle;
}
public Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
public class BookshelfBanner implements Cloneable {
/**
* 標題
*/
public String title;
/**
* banner圖片url
*/
public String banner;
/**
* 廣告實體
*/
public AdEntity adEntity;
public BookshelfBanner(String title, AdEntity adEntity) {
this.title = title;
this.adEntity = adEntity;
}
/**
* 淺拷貝
* @return
*/
public Object clone() {
BookshelfBanner o = null;
try {
o = (BookshelfBanner) super.clone();
} catch (CloneNotSupportedException e) {
e.fillInStackTrace();
}
return o;
}
}
public class Test {
public static void main(String[] args) {
AdEntity adEntity = new AdEntity("小書亭");
BookshelfBanner banner1 = new BookshelfBanner("小書亭下載", adEntity);
BookshelfBanner banner2 = (BookshelfBanner) banner1.clone();
// banner2.adEntity.adTitle == "小書亭"
adEntity.adTitle = "小書亭改名啦"; // adEntity引用的adTitle改變了
// banner2.adEntity.adTitle == "小書亭改名啦" // 淺拷貝adEntity,會被修改
}
}
3 深拷貝
3.1 深拷貝是什麼?
深拷貝:對象A複製出一個對象B來,修改對象B中的8中基本類型(包括裝箱)的值和String,對象A中不被修改。修改對象B中的引用對象,由於引用對象是新創建對象,對象A中的引用對象不會被修改。
3.2 例子
public class AdEntity implements Cloneable {
public String adTitle;
public AdEntity(String adTitle) {
this.adTitle = adTitle;
}
public Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
public class BookshelfBanner implements Cloneable {
/**
* 標題
*/
public String title;
/**
* banner圖片url
*/
public String banner;
/**
* 廣告實體
*/
public AdEntity adEntity;
public BookshelfBanner(String title, AdEntity adEntity) {
this.title = title;
this.adEntity = adEntity;
}
/**
* 深拷貝
*
* @return
*/
public Object clone() {
BookshelfBanner o = null;
try {
o = (BookshelfBanner) super.clone();
if (adEntity != null) {
o.adEntity = (AdEntity) adEntity.clone();
}
} catch (CloneNotSupportedException e) {
e.fillInStackTrace();
}
return o;
}
}
public class Test {
public static void main(String[] args) {
AdEntity adEntity = new AdEntity("小書亭");
BookshelfBanner banner1 = new BookshelfBanner("小書亭下載", adEntity);
BookshelfBanner banner2 = (BookshelfBanner) banner1.clone();
// banner2.adEntity.adTitle == "小書亭"
adEntity.adTitle = "小書亭改名啦"; // adEntity引用的adTitle改變了
// banner2.adEntity.adTitle == "小書亭" // 深拷貝adEntity,不會被修改
}
}
4 還有一種深拷貝方法,將對象序列化
4.1 對象序列化是什麼?
對象序列化卻很耗時,在一些框架中,我們便可以感受到,它們往往將對象進行串行化後進行傳遞,耗時較多。
4.2 例子
public class AdEntity implements Serializable {
public String adTitle;
public AdEntity(String adTitle) {
this.adTitle = adTitle;
}
public Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
public class BookshelfBanner implements Serializable {
/**
* 標題
*/
public String title;
/**
* banner圖片url
*/
public String banner;
/**
* 廣告實體
*/
public AdEntity adEntity;
public BookshelfBanner(String title, AdEntity adEntity) {
this.title = title;
this.adEntity = adEntity;
}
/**
* 深拷貝
*
* @return
*/
public Object deepClone() throws IOException, OptionalDataException, 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());
}
}
public class Test {
public static void main(String[] args) {
AdEntity adEntity = new AdEntity("小書亭");
BookshelfBanner banner1 = new BookshelfBanner("小書亭下載", adEntity);
BookshelfBanner banner2 = (BookshelfBanner) banner1.deepClone();
// banner2.adEntity.adTitle == "小書亭"
adEntity.adTitle = "小書亭改名啦"; // adEntity引用的adTitle改變了
// banner2.adEntity.adTitle == "小書亭" // 深拷貝adEntity,不會被修改
}
}