浅拷贝是指复制对象时,只复制对象本身所包含的值类型字段,并将引用类型字段简单地复制一份引用,而不是复制引用的对象内容。这意味着新旧对象中的引用类型字段指向相同的内存地址。因此,对任何一方引用类型的字段做出修改都会影响到另一个对象。
举例说明:
class Person
{
public string Name { get; set; } // 值类型属性,字符串实际上是引用类型,但在此处作为不可变对象讨论
public Car CarOwned { get; set; } // 引用类型属性
}
class Car
{
public string Brand { get; set; }
}
// 创建原始对象
var originalPerson = new Person { Name = "Alice", CarOwned = new Car { Brand = "Toyota" } };
var shallowCopyPerson = originalPerson.MemberwiseClone(); // 使用默认的浅拷贝方法
// 修改浅拷贝后的引用类型字段
shallowCopyPerson.CarOwned.Brand = "Ford";
// 输出结果会显示两个对象的CarOwned.Brand都为"Frod"
Console.WriteLine(originalPerson.CarOwned.Brand); // 输出 "Ford"
Console.WriteLine(shallowCopyPerson.CarOwned.Brand); // 输出 "Ford"
在这个例子中,MemberwiseClone()
方法执行了浅拷贝操作,虽然 Person
对象被复制了一份,但 CarOwned
这个引用类型的字段并没有创建新的 Car
实例,而是共享了同一个实例。
深拷贝则不仅复制值类型字段,还复制引用类型字段所引用的对象,并为这些对象分配新的内存空间。这样一来,修改深拷贝后对象的引用类型字段不会影响到原对象。
深拷贝需要程序员自定义实现,通常涉及到递归遍历所有引用类型字段并逐一复制其内容。例如:
class Person
{
public string Name { get; set; }
public Car CarOwned { get; set; }
// 自定义深拷贝方法
public Person DeepCopy()
{
var copy = (Person)this.MemberwiseClone();
if (this.CarOwned != null)
copy.CarOwned = new Car { Brand = this.CarOwned.Brand }; // 深拷贝Car对象
return copy;
}
}
class Car
{
public string Brand { get; set; }
}
// 创建原始对象
var originalPerson = new Person { Name = "Alice", CarOwned = new Car { Brand = "Toyota" } };
var deepCopyPerson = originalPerson.DeepCopy();
// 修改深拷贝后的引用类型字段
deepCopyPerson.CarOwned.Brand = "Ford";
// 输出结果会显示原对象的CarOwned.Brand仍然是"Toyota"
Console.WriteLine(originalPerson.CarOwned.Brand); // 输出 "Toyota"
Console.WriteLine(deepCopyPerson.CarOwned.Brand); // 输出 "Ford"
在上述深拷贝示例中,DeepCopy()
方法手动创建了 Car
类的新实例,这样 originalPerson
和 deepCopyPerson
就拥有各自独立的 Car
对象,修改其中一个不会影响另一个。
浅拷贝(Shallow Copy)和直接赋值在处理引用类型变量时,其实是有相似之处的,但也有微妙的区别:
直接赋值:
当一个对象被直接赋值给另一个变量时,实际上创建的是原对象的一个引用副本。这意味着新变量和原变量都指向同一个内存地址,对于值类型而言,效果等同于复制了实际数据;而对于引用类型,只是复制了对原始对象的引用。
例如,在C#中:
class MyClass
{
public string Value;
}
MyClass obj1 = new MyClass { Value = "Hello" };
MyClass obj2 = obj1; // 直接赋值
obj2.Value = "World"; // 改变 obj2 的 Value 属性
在此例中,obj2
是 obj1
的引用副本,所以改变 obj2.Value
会导致 obj1.Value
同样变为 “World”,因为它们共享同一份引用类型的内部状态。
浅拷贝:
浅拷贝同样是创建了一个新的对象,并且复制了原对象的所有非引用类型字段值和引用类型的引用。与直接赋值类似,浅拷贝后的引用类型成员仍然指向原来的引用类型的实例。
例如,使用C#中的 MemberwiseClone()
方法进行浅拷贝:
class MyClass
{
public string Value;
public AnotherClass ReferenceTypeField;
public MyClass ShallowCopy()
{
return (MyClass)this.MemberwiseClone();
}
}
class AnotherClass { /* ... */ }
MyClass obj1 = new MyClass { Value = "Hello", ReferenceTypeField = new AnotherClass() };
MyClass obj3 = obj1.ShallowCopy(); // 浅拷贝
obj3.Value = "World"; // 改变 obj3 的 Value 属性
obj3.ReferenceTypeField.SomeProperty = "New Value"; // 改变引用类型字段属性
// 这里,obj1.Value 不受影响,但 obj1.ReferenceTypeField.SomeProperty 会被修改
在这个例子中,虽然 obj3
是 obj1
的浅拷贝,改变了 obj3.Value
并不影响 obj1.Value
,因为这里 Value
是值类型(字符串在.NET中是不可变类型)。然而,ReferenceTypeField
在 obj1
和 obj3
中指向的是同一个 AnotherClass
实例,因此更改 obj3.ReferenceTypeField
的属性会影响到 obj1.ReferenceTypeField
。
总结:
python推荐学习汇总连接:
50个开发必备的Python经典脚本(1-10)
50个开发必备的Python经典脚本(41-50)
————————————————
?最后我们放松一下眼睛