2013-11-23 268 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(); 
     } 
    } 
}