大多数程序现在都用 泛型集合类型 而非数组来存储数据集合。
“shallow copy”=copy;“deep copy”=clone
值类型没有改变。不发生跟随改变。
using System;
namespace Array的copy和Clone
{
class Program
{
static void Main(string[] args)
{
test01();
Console.WriteLine("Hello World!");
Console.ReadLine();
}
static void test01()
{
int[] a = new int[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
int[] b =new int[10];
Array.Copy(a, 3, b, 2, 5);
int[] c = (int[])a.Clone();
a[4] = 99;
for (int i = 0; i < a.Length; i++)
{
Console.WriteLine(a[i]);
}
Console.WriteLine("______________------___________");
for (int i = 0; i < b.Length; i++)
{
Console.WriteLine(b[i]);
}
Console.WriteLine("______________------___________");
for (int i = 0; i < c.Length; i++)
{
Console.WriteLine(c[i]);
}
}
}
}
输出:
0
1
2
3
99
5
6
7
8
9
______________------___________
0
0
3
4
5
6
7
0
0
0
______________------___________
0
1
2
3
4
5
6
7
8
9
Hello World!
Clone说是浅拷贝。
Clone说是浅拷贝。
我的理解是不是说直接把引用拷贝过去了。应该随变(随之改变)的。考虑到int是值类型,存储在栈区上面,不存在引用一说。
Copy直接要求必须输入一个新的Array,所以这个好理解,肯定不会随变的。真是这样吗?
现在的问题就剩下一个了。需要引用类型的例子。
我们需要自建一个新的类型Class来重新实验,比如Array中存储的是Person,Person存储一个字段是string类型的名字。
看代码:增加一个新类Person,引用类型,存储在堆中。可引用。
using System;
namespace Array的copy和Clone
{
class Program
{
static void Main(string[] args)
{
// test01();
test02();
Console.WriteLine("Hello World!");
Console.ReadLine();
}
static void test01()
{
int[] a = new int[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
int[] b =new int[10];
Array.Copy(a, 3, b, 2, 5);
int[] c = (int[])a.Clone();
a[4] = 99;
for (int i = 0; i < a.Length; i++)
{
Console.WriteLine(a[i]);
}
Console.WriteLine("______________Copy结果:___________");
for (int i = 0; i < b.Length; i++)
{
Console.WriteLine(b[i]);
}
Console.WriteLine("______________Clone结果:___________");
for (int i = 0; i < c.Length; i++)
{
Console.WriteLine(c[i]);
}
}
static void test02()
{
Person[] p1 = new Person[]
{
new Person("Tom1"),
new Person("Tom2"),
new Person("Tom3"),
new Person("Tom4"),
new Person("Tom5"),
new Person("Tom6"),
};
Person[] p2 = new Person[5];
Array.Copy(p1, p2, 5);
Person[] p3 = (Person[])p1.Clone();
p1[3].name = "Jack00";
for (int i = 0; i < p1.Length; i++)
{
Console.WriteLine(p1[i].name);
}
Console.WriteLine("______________------___________");
for (int i = 0; i < p2.Length; i++)
{
Console.WriteLine(p2[i].name);
}
Console.WriteLine("______________------___________");
for (int i = 0; i < p3.Length; i++)
{
Console.WriteLine(p3[i].name);
}
}
}
class Person
{
public string name;
public Person(string name)
{
this.name = name;
}
}
}
输出:
Tom1
Tom2
Tom3
Jack00
Tom5
Tom6
______________Copy结果:___________
Tom1
Tom2
Tom3
Jack00
Tom5
______________Clone结果:___________
Tom1
Tom2
Tom3
Jack00
Tom5
Tom6
Hello World!
看结果知道:联动了,随之改变(随变)。
但是copy和Clone都随之改变而改变。
我们准备好了一切,并做了猜测,发现错了。
方法调用时如何?
using System;
namespace Array的copy和Clone
{
class Program
{
static void Main(string[] args)
{
// test01();
test02();
Console.WriteLine("Hello World!");
Console.ReadLine();
}
static void test01()
{
int[] a = new int[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
int[] b =new int[10];
Array.Copy(a, 3, b, 2, 5);
int[] c = (int[])a.Clone();
a[4] = 99;
for (int i = 0; i < a.Length; i++)
{
Console.WriteLine(a[i]);
}
Console.WriteLine("______________------___________");
for (int i = 0; i < b.Length; i++)
{
Console.WriteLine(b[i]);
}
Console.WriteLine("______________------___________");
for (int i = 0; i < c.Length; i++)
{
Console.WriteLine(c[i]);
}
}
static void test02()
{
Person[] p1 = new Person[]
{
new Person("Tom1"),
new Person("Tom2"),
new Person("Tom3"),
new Person("Tom4"),
new Person("Tom5"),
new Person("Tom6"),
};
Person[] p2 = new Person[5];
Array.Copy(p1, p2, 5);
Person[] p3 = (Person[])p1.Clone();
PrintArray1(p1);
PrintArray2(p2);
PrintArray3(p3);
Console.WriteLine("------------------------华丽分割线----------------");
for (int i = 0; i < p1.Length; i++)
{
if (i==3)
{
p1[3].name = "Jack01";
}
Console.WriteLine(p1[i].name);
}
Console.WriteLine("______________Copy结果:___________");
for (int i = 0; i < p2.Length; i++)
{
Console.WriteLine(p2[i].name);
}
Console.WriteLine("______________Clone结果:___________");
for (int i = 0; i < p3.Length; i++)
{
Console.WriteLine(p3[i].name);
}
}
static void PrintArray1(Person[] array)
{
for (int i = 0; i < array.Length; i++)
{
if (i == 3)
{
array[3].name = "Jack00";
}
Console.WriteLine(array[i].name);
}
}
static void PrintArray2(Person[] array)
{
for (int i = 0; i < array.Length; i++)
{
Console.WriteLine(array[i].name);
}
}
}
class Person
{
public string name;
public Person(string name)
{
this.name = name;
}
}
}
输出:
Tom1
Tom2
Tom3
Jack00
Tom5
Tom6
Tom1
Tom2
Tom3
Jack00
Tom5
Tom1
Tom2
Tom3
Jack00
Tom5
Tom6
------------------------华丽分割线----------------
Tom1
Tom2
Tom3
Jack01
Tom5
Tom6
______________Copy结果:___________
Tom1
Tom2
Tom3
Jack01
Tom5
______________Clone结果:___________
Tom1
Tom2
Tom3
Jack01
Tom5
Tom6
Hello World!
引用类型通过copy和Clone复制后都随变。 即使是发生了方法调用。
三者联动:
using System;
namespace Array的copy和Clone
{
class Program
{
static void Main(string[] args)
{
// test01();
test02();
Console.WriteLine("Hello World!");
Console.ReadLine();
}
static void test01()
{
int[] a = new int[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
int[] b =new int[10];
Array.Copy(a, 3, b, 2, 5);
int[] c = (int[])a.Clone();
a[4] = 99;
for (int i = 0; i < a.Length; i++)
{
Console.WriteLine(a[i]);
}
Console.WriteLine("______________------___________");
for (int i = 0; i < b.Length; i++)
{
Console.WriteLine(b[i]);
}
Console.WriteLine("______________------___________");
for (int i = 0; i < c.Length; i++)
{
Console.WriteLine(c[i]);
}
}
static void test02()
{
Person[] p1 = new Person[]
{
new Person("Tom1"),
new Person("Tom2"),
new Person("Tom3"),
new Person("Tom4"),
new Person("Tom5"),
new Person("Tom6"),
};
Person[] p2 = new Person[5];
Array.Copy(p1, p2, 5);
Person[] p3 = (Person[])p1.Clone();
Console.WriteLine("----P1:----");
PrintArray1(p1);
Console.WriteLine("----P2:----");
PrintArray2(p2);
Console.WriteLine("----P3:----");
PrintArray3(p3);
Console.WriteLine("------------------------华丽分割线----------------");
for (int i = 0; i < p1.Length; i++)
{
if (i==3)
{
p1[3].name = "Jack01";
}
Console.WriteLine(p1[i].name);
}
Console.WriteLine("______________Copy结果:___________");
for (int i = 0; i < p2.Length; i++)
{
Console.WriteLine(p2[i].name);
}
Console.WriteLine("______________Clone结果:___________");
for (int i = 0; i < p3.Length; i++)
{
Console.WriteLine(p3[i].name);
}
}
static void PrintArray1(Person[] array)
{
for (int i = 0; i < array.Length; i++)
{
if (i == 3)
{
array[3].name = "Jack00";
}
Console.WriteLine(array[i].name);
}
}
static void PrintArray2(Person[] array)
{
for (int i = 0; i < array.Length; i++)
{
if (i == 1)
{
array[1].name = "Jack02改变他";
}
Console.WriteLine(array[i].name);
}
}
static void PrintArray3(Person[] array)
{
for (int i = 0; i < array.Length; i++)
{
if (i == 2)
{
array[2].name = "Jack03改变他";
}
Console.WriteLine(array[i].name);
}
}
}
class Person
{
public string name;
public Person(string name)
{
this.name = name;
}
}
}
输出:
----P1:----
Tom1
Tom2
Tom3
Jack00
Tom5
Tom6
----P2:----
Tom1
Jack02改变他
Tom3
Jack00
Tom5
----P3:----
Tom1
Jack02改变他
Jack03改变他
Jack00
Tom5
Tom6
------------------------华丽分割线----------------
Tom1
Jack02改变他
Jack03改变他
Jack01
Tom5
Tom6
______________Copy结果:___________
Tom1
Jack02改变他
Jack03改变他
Jack01
Tom5
______________Clone结果:___________
Tom1
Jack02改变他
Jack03改变他
Jack01
Tom5
Tom6
Hello World!
指向同一地址:仅仅只是引用的传递,引用名称(栈中变量名和栈中位置)虽然变了,但是栈中变量指向的堆中地址(栈中记录的Array所在的堆中地址)还是同一个。
结论:
请牢记:这俩(Copy和Clone)
- 对值拷贝:不联动。
- 对引用的拷贝,都是联动改变的。随变。