C#/.NET(26): 얕은 복사와 깊은 복사
값 타입과 참조 타입은 얕은 복사와 깊은 복사 방식이 다르다.
얕은 복사를 할 때, 값 타입은 복사되어진다.
하지만 참조 타입 멤버들은 동일한 참조값만 복사되어진다. 그래서 복사된 참조 타입은 메모리상에서 같은 오브젝트를 가리키게 된다.
반면에 깊은 복사를 할 때, 참조 타입은 각각 새로운 참조가 만들어지고 속해야 되는 새로운 오브젝트에로 전달된다.
그래서 참조 타입은 깊은 복사를 하면, 다른 오브젝트를 가리킬 수 있게 된다.

[얕은 복사 - 예시 코드]
위에서 다루었던 내용대로, 얕은 복사를 할 때, 값 타입(Height)은 복사되어 새로 생성된 객체에 속하게 된다.
하지만, 참조 타입(Pet)은 동일한 참조값이 복사되고 복사되어진 참조값은 생성된 객체 Man과 ManShallowCopy에 참조되어, 결국 동일한 객체 Pet을 가리키게 된다.
using System;
namespace ShallowCopVSDeepCopy
{
class Person
{
public string Name;
public double Height;
public Pet Pet;
public Person(string name, double height, Pet pet)
{
Name = name;
Height = height;
Pet = pet;
}
// 얕은 복사 MemberwiseClone(): 값 타입은 복사, 참조 타입은 참조값만 복사
public Person ShallowCopy()
{
return (Person)MemberwiseClone();
}
}
class Pet
{
public string Name;
public double Height;
public Pet(string name, double height)
{
Name = name;
Height = height;
}
}
internal class Program
{
static void Main(string[] args)
{
var Man = new Person("이동규", 174.5, new Pet("해피", 4.5));
var ManShallowCopy = Man.ShallowCopy();
Man.Pet.Height = 10;
ManShallowCopy.Height = 190.5;
// 값 타입과 참조 타입의 얕은 복사 비교 출력
Console.WriteLine($"Man's Pet's Height: { Man.Pet.Height} " +
$"/ ManShallowCopy's Pet's Height: {ManShallowCopy.Pet.Height}");
Console.WriteLine($"Man's Height: {Man.Height} " +
$"/ ManShallowCopy's Height: {ManShallowCopy.Height}");
}
}
}
Man's Pet's Height: 10 / ManShallowCopy's Pet's Height: 10
Man's Height: 174.5 / ManShallowCopy's Height: 190.5
[깊은 복사 - 예시 코드]
깊은 복사를 할 때, 참조 타입(Pet)은 동일한 참조값이 복사되어지는 것이 아니라, 각각 새로운 참조가 만들어지고 속해야 하는 새로운 객체(Woman, WomanDeepCopy)에 전달된다.
깊은 복사는 참조 타입이 다른 오브젝트를 가리킬 수 있게 해주지만, 직접 깊은 복사를 정의해주어야 한다.
예시 코드는 아래와 같다.
using System;
namespace ShallowCopVSDeepCopy
{
class Person
{
public string Name;
public double Height;
public Pet Pet;
public Person(string name, double height, Pet pet)
{
Name = name;
Height = height;
Pet = pet;
}
// 얕은 복사 MemberwiseClone(): 값 타입은 복사, 참조 타입은 참조값만 복사
//public Person ShallowCopy()
//{
// return (Person)MemberwiseClone();
//}
// 깊은 복사는 직접 정의해야 함.
public Person DeepCopy()
{
return new Person(Name, Height, new Pet(Pet.Name, Pet.Height));
}
}
class Pet
{
public string Name;
public double Height;
public Pet(string name, double height)
{
Name = name;
Height = height;
}
}
internal class Program
{
static void Main(string[] args)
{
//var Man = new Person("이동규", 174.5, new Pet("해피", 4.5));
//var ManShallowCopy = Man.ShallowCopy();
//Man.Pet.Height = 10;
//ManShallowCopy.Height = 190.5;
//// 값 타입과 참조 타입의 얕은 복사 비교 출력
//Console.WriteLine($"Man's Pet's Height: { Man.Pet.Height} " +
// $"/ ManShallowCopy's Pet's Height: {ManShallowCopy.Pet.Height}");
//Console.WriteLine($"Man's Height: {Man.Height} " +
// $"/ ManShallowCopy's Height: {ManShallowCopy.Height}");
//Console.WriteLine();
var Woman = new Person("정은정", 165.5, new Pet("럭키", 5.5));
var WomanDeepCopy = Woman.DeepCopy();
Woman.Pet.Height = 6.5;
WomanDeepCopy.Height = 145.8;
// 값 타입과 참조 타입의 깊은 복사 비교 출력
Console.WriteLine($"Woman's Pet's Height: {Woman.Pet.Height} " +
$"/ WomanDeepCopy's Pet's Height: {WomanDeepCopy.Pet.Height}");
Console.WriteLine($"Woman's Height: {Woman.Height} " +
$"/ WomanDeepCopy's Height: {WomanDeepCopy.Height}");
}
}
}
Woman's Pet's Height: 6.5 / WomanDeepCopy's Pet's Height: 5.5
Woman's Height: 165.5 / WomanDeepCopy's Height: 145.8
정리
지난 블로그에서 == 연산자와 Equals() 메소드는 참조값만을 비교해준다는 것을 알 수 있었다. 그래서, 값 타입끼리 동일한지 비교하기 위해서는 Equals() 메소드를 오버라이드 해주어야 객체에 담긴 content를 비교할 수 있음을 알게 되었다.
이번에 연구한 내용도 비슷한 맥락인데, 얕은 복사는 참조 타입의 경우 참조값만을 복사하여 전달하기 때문에, 동일한 객체를 가리켜 얕게 복사한 객체의 멤버를 수정할 경우 전체 코드에 영향을 줄 수가 있다.
하지만 깊은 복사는 값 타입의 경우 새로 생성한 객체로 복사되어, 일부를 수정하더라도 전체 코드에 영향을 주지 않게 된다.
댓글남기기