《**> 問題
有時需要建立乙個自定義型別,它能為開發人員提供一種簡單的機制來建立該型別例項的副本。
解決方案
實現system.icloneable介面。
原理
如果我們有兩個值型別的變數,將其中乙個變數的值賦給另乙個,實際上會建立該值的乙個副本,這個副本與原來的值沒有什麼關係——這意味著改變其中乙個的值不會影響另乙個變數的值。而如果是兩個引用型別的變數,其中乙個變數的值賦給另乙個的話(不包括string型別,clr會對其有特殊處理),並沒有建立值的副本,而是使兩個變數執行同乙個物件——這意味著改變物件的值會同時影響兩個變數。要真正地建立引用型別的副本,我們必須轉殖(clone)變數指向的物件。
實現icloneable介面使乙個型別成為可轉殖的(cloneable),這需要提供clone方法來提供該型別的物件的副本。clone方法不接受任何引數,返回object型別的物件(不管是何種型別實現該介面)。所以我們獲得副本後仍需要進行顯式地轉換。
實現icloneable介面的方式取決於我們的型別的資料成員。如果型別僅包含值型別(int,byte等型別)和string型別的資料成員,我們只要在clone方法中初始化乙個新的物件,將其的資料成員設定為當前物件的各個成員的值即可。事實上,object類的memberwiseclone方法會自動完成該過程。
如果自定義型別包含引用型別的資料成員,必須考慮clone方法是實現淺拷貝(shallowcopy)還是深拷貝(deepcopy)。淺拷貝是指副本物件中的引用型別的資料成員與源物件的資料成員指向相同的物件。而如果是深拷貝,則必須建立整個物件的結構,副本物件中的引用型別的資料成員與源物件的資料成員指向不同的物件。
淺拷貝是容易實現的,就是使用前面提到的memberwiseclone方法。開發人員往往希望使用的型別能夠實現深拷貝,但會發現這樣的型別並不多。這種情況在system.collections命名空間中尤其常見,這裡面的類在其clone方法中實現的都是淺拷貝。這麼做主要出於兩個原因:
建立乙個大物件的副本對效能影響較大;
通用的集合型別可能會包含各種各樣的物件,在這種情況下實現深拷貝並不可行,因為集合中的物件並非都是可轉殖的,另外還存在迴圈引用的情況,這會讓深拷貝過程陷入死迴圈。
對於強型別的集合情況有所不同,因為它包含的元素是可控制的,此時深拷貝變得有用,同時也是可行的。例如system.xml.xmlnode在其clone方法中實現了深拷貝。
另外,如果需要轉殖乙個未實現icloneable介面卻是可序列化的物件,通常可以通過序列化和反序列化來達到轉殖的效果。但要小心,序列化過程不一定會序列化所以資料成員。
**
下面的**示例描述了轉殖的各種方法。簡單的employee類僅僅包含string和int型別的成員,所以使用object型別的memberwiseclone方法建立副本。team類的clone方法實現了深拷貝,它包含了乙個employee物件的集合,同時team類提供了乙個私有的建構函式用以簡化clone方法的**。建構函式的這種用法是簡化轉殖過程的一種常見方式。
public
class
employee : icloneable
public
object
clone()
public
override
string
tostring()
() - age
", name, title, age);}}
team類**:
public
class
team : icloneable
private
team(list
<
employee
>
members)}//
adds an employee object to the team.
public
void
addmember(employee member)
//override object.tostring method to return a string representation of the team.
public
override
string
tostring()
\r\n
", e);
}return
sb.tostring();}//
implementation of icloneable.clone.
public
object
clone()}
測試**:
//create the original team.
team team
=new
team();
team.addmember(
newemployee(
"anders",
"developer",
26));
team.addmember(
newemployee(
"bill",
"developer",
46));
team.addmember(
newemployee(
"steve",
"ceo",
36));
team clone
=team.clone()
asteam;
//display the original team.
console.writeline(
"original team:");
console.writeline(team);
//display the cloned team.
console.writeline(
"clone team:");
console.writeline(clone);
//make changes.
console.writeline(
"*** make a change to original team ***");
console.writeline(environment.newline);
team.teammembers[
0].title ="
pm";team.teammembers[
0].age =30
;//display the original team.
console.writeline(
"original team:");
console.writeline(team);
//display the cloned team.
console.writeline(
"clone team:");
console.writeline(clone);
C 實現可轉殖(ICloneable)的型別
問題有時需要建立乙個自定義型別,它能為開發人員提供一種簡單的機制來建立該型別例項的副本。解決方案 實現system.icloneable介面。原理 如果我們有兩個值型別的變數,將其中乙個變數的值賦給另乙個,實際上會建立該值的乙個副本,這個副本與原來的值沒有什麼關係 這意味著改變其中乙個的值不會影響另...
java物件完全轉殖有法可遵
jsp頁面的值是通過struts的action注入的pojo實體類屬性來賦值的 例如 頁面有.等等控制項,他們的值都進行了類似的繫結。那麼在對應的action中必然有users類的物件users與之對應,且有setter和getter方法。那麼關鍵來了,這個時候,我們頁面要做乙個修改功能,通常我們的...
c 深轉殖與淺轉殖
我們都知道memberwiseclone 會將淺轉殖。什麼是淺轉殖?如何深轉殖呢?public class good private static good good private static good good new good public good createinstance publi...