2013-11-23 45 views
2

克隆是一種淺拷貝的方式。字符串是一個引用類型。爲什麼s2的變化不會影響s1?方法Array.Clone是淺拷貝?

private void button3_Click(object sender, EventArgs e) 
    { 
     string[] s1 = { "a", "b" }; 
     string[] s2 = new string[2]; 

     s2 = (string[])s1.Clone(); 
     //s2=s1; //when Direct assignment s1 changed too 
     s2[1] = "e"; 
     foreach (var s in s1) 
     { 
      this.richTextBox1.Text += s+","; 
     } 
     this.richTextBox1.Text += System.Environment.NewLine; 

     foreach (var s in s2) 
     { 
      this.richTextBox1.Text += s + ","; 
     } 
    } 
} 

輸出: A,B, A,E, 時淺拷貝,它應該是:A,E,A,E

+0

但S2 = S1它worked.when改變S2,S1變化太大 – SleeplessKnight

+0

是要認識到,以S1 S2分配不淺拷貝是很重要的,而是讓S2點S1,有效地使S2的指針。淺拷貝意味着創建一個新數組並將指向每個對象的指針複製到新數組中 – Qwerty01

+0

任何人都知道如何將問題作爲投票問題,我對這個問題感到困惑 – SleeplessKnight

回答

4

當你克隆s1s2,這些都是兩個完全分開的物體,住在不同的地點。

s1[1]保持到保持b位置的引用,象s2[1]。然後您分配一個不同的參考s2[1] - 一個到不同的位置。這不會以任何方式影響s1[1]

畢竟,您還沒有改變保存b的位置。


當您指定s2 = s1;,兩個變量指向同一個對象 - 當您更改對象,這兩個變量將反映這種變化,因爲它們指向同一個地方。

+0

他要求一個淺拷貝(例如,兩個數組都包含相同的對象),檢查我的文章爲什麼它不工作。 – Qwerty01

2

無論淺拷貝還是深拷貝,拷貝總是會創建一個新實例。這意味着更改複製的對象不會影響原始對象。請注意,當我說更改複製的對象,我的意思是你分配一些元素到一個全新的實例。如果你只是改變該元素的某些屬性,它可以反映原始數組中的相應元素(當然如果元素類型是引用類型)。但在這種情況下,元素只是一個字符串,它是不可變的,我們不能改變任何東西。

關於淺拷貝和深拷貝,這裏是一個小的MSDN

陣列只複製數組的元素,無論是引用類型還是值類型,但它的淺表副本不要複製引用引用的對象。新數組中的引用指向與原始數組中的引用指向的相同對象。

相比之下,Array的深層副本會複製由元素直接或間接引用的元素和所有內容。

我想強調更多元件的這種更改屬性不會意味着改變陣列。而改變一個數組意味着你必須分配一些元素到一個全新的實例

+0

這不是事實。對於參考類型的淺拷貝確實會相互影響。 –

+0

@RohitVats當我們訪問某個元素並**更改該元素的某些屬性時** - >是它會更改原始值,但在這種情況下,您能告訴我**我們可以在字符串上更改哪些屬性?** –

+0

你在答案中沒有提到有關字符串。 '無論淺拷貝還是深拷貝,拷貝總是會創建一個新的實例。「 - >這種說法通常並不正確,這正是我想說的。 –

2

由於字符串是不可變的,這意味着它們不能被分配到(更多信息在Why .NET String is immutable?),所以你所要求的是不可能的,因此每次分配一個字符串時,它實際上都會創建一個新字符串並替換該對象。

如果您想要達到預期的效果,您可能需要將s2指定給s1,這將使它們指向相同的數組,並且具有所需的效果。


的淺表副本的一個例子是: (假設label1和label2定義)

Label[] s1 = new Label[2]; 
Label[] s2 = new Label[2]; 
s1[0] = label1; 
s1[1] = label2; 
for (int i = 0; i < s1.Length; i++) 
    s2[i] = s1[i]; 
s2[1].Text = "asdf"; 

最終導致S1 [1]的Text屬性將被更改爲「ASDF 「因爲即使數組不同,s1 [1]和s2 [1]也指向相同的對象。由於對象s2 [1]指向的內容正在改變(基本上是什麼s2 [1] =「asdf」;在做什麼,所以s2 [1] = new Label()不會改變s1 [1] OP的代碼),但這是任何淺拷貝的限制。

+0

你能否給我一個正確的方式,用2個字符串排列 – SleeplessKnight

+0

淺拷貝或給我一個沒有字符串的淺拷貝演示。謝謝 – SleeplessKnight

+0

我不明白'string'是不可變的這個事實怎麼改變什麼。賦值是賦值,對於任何引用類型都是完全相同的。 – svick

0

運行下面的程序。我想我是對的。 CopyTo和Clone都在執行卷影複製。

namespace ConsoleApplication5 
{ 
    public class Person 
    { 
     public static void Main(string[] args) 
     { 
      StringBuilder a = new StringBuilder("Vish"); 
      StringBuilder b = new StringBuilder("Krish"); 
      StringBuilder[] arr = new StringBuilder[2] { a,b }; 
      StringBuilder[] copied = new StringBuilder[2]; 


      arr.CopyTo(copied, 0); 

      StringBuilder[] cloned = arr.Clone() as StringBuilder[]; 

      Console.WriteLine(); 

      copied[1] = copied[1].Append("_AppendedCopy"); 
      cloned[1] = cloned[1].Append("_AppendedClone"); 

      for (int i = 0; i < arr.Length; i++) 
       Console.WriteLine(arr[i]); 
      Console.WriteLine(); 
      for (int i = 0; i < copied.Length; i++) 
       Console.WriteLine(copied[i]); 
      Console.WriteLine(); 

      for (int i = 0; i < cloned.Length; i++) 
       Console.WriteLine(cloned[i]); 
      Console.WriteLine(); 

      Console.ReadKey(); 
     } 
    } 
}