딥 카피와 얕은 카피의 차이점은 무엇입니까?
딥 카피와 얕은 카피의 차이점은 무엇입니까?
얕은 복사본은 가능한 한 적게 복제합니다. 컬렉션의 단순 복사본은 요소가 아닌 컬렉션 구조의 복사본입니다. 얕은 사본을 사용하면 이제 두 컬렉션이 식별 요소를 공유합니다.
딥 카피는 모든 것을 복제합니다. 컬렉션의 전체 복사본은 원본 컬렉션의 모든 요소가 복제 된 두 컬렉션입니다.
폭 대 깊이; 객체를 루트 노드로 사용하는 참조 트리의 관점에서 생각하십시오.
얕은 :
변수 A와 B는 서로 다른 메모리 영역을 할당 며, B가 A에 할당 된 두 변수는 메모리 영역을 나타냅니다. 나중에 둘 중 하나의 내용을 수정하면 내용을 공유하는 다른 사람의 내용에 즉시 반영됩니다.
깊은 :
변수 A와 B는 메모리의 다른 영역을 할당하고, B가 A에 할당 된 A가 메모리 영역의 값이 할당됩니다. 나중에 내용에 대한 수정은 A 또는 B에 고유합니다. 내용은 공유되지 않습니다.
요컨대, 그것은 무엇을 대상에 달려 있습니다. 얕은 복사본에서 개체 B는 메모리에서 개체 A의 위치를 가리. 딥 복사에서는 A의 메모리 위치에있는 모든 항목이 객체에서 복사됩니다.
이 위키 기사에는 훌륭한 다이어그램이 있습니다.
http://en.wikipedia.org/wiki/Object_copy
다음 이미지를 고려하십시오
예를 들어 Object.MemberwiseClone는 생성 얕은의 복사 링크를
및 사용 ICloneable 인터페이스 당신이 얻을 수있는 깊은 설명 된대로 사본을 여기에
특히 iOS 개발자의 경우 :
경우 B
A는 얕은 복사 의 A
그 것처럼 원시 데이터를 다음 B = [A assign];
과 같이의 개체에 대한 B = [A retain]
;
B와 A는 동일한 메모리 위치를 가리고 있습니다.
경우 B
A는 딥 카피 의가 A
, 다음은 같다B = [A copy];
B와 A는 다른 메모리 위치를 가리 킵니다.
B 메모리 주소는 A와 동일합니다.
B는 A와 같은 내용을 가지고 있습니다.
얕은 복사 : 한 개체에서 다른 개체로 멤버 값을 복사합니다.
전체 복사 : 한의 멤버 값을 다른 개체로 복사합니다.
모든 포인터 개체가 복제되고 딥 복사됩니다.
예 :
class String
{
int size;
char* data;
};
String s1("Ace"); // s1.size = 3 s1.data=0x0000F000
String s2 = shallowCopy(s1);
// s2.size =3 s2.data = 0X0000F000
String s3 = deepCopy(s1);
// s3.size =3 s3.data = 0x0000F00F
// (With Ace copied to this location.)
여기에서 짧고 이해하기 쉬운 대답을 보지 못 시도해 보겠습니다.
얕은 복사본을 사용하면 원본이 모든 개체도 대상으로 지정되지 않은 개체가 복사됩니다.
전체 복사를 사용하면 원본이 모든 개체가 복사되고 복사본은 대상이 된 것입니다 (이제 참조 각 개체가 2 개가됩니다). 이것은 오브젝트 트리에서 반복됩니다.
이해를 쉽게하기 위해 https://www.cs.utexas.edu/~scottm/cs307/handouts/deepCopying.htm 문서를 따를 수 있습니다.
얕은 복사 :
딥 카피 :
{두하고 상상을 상상해보세요 : A와 B가 같은 유형 _t (C ++와 관련된 생각)이고 A에서 B 로의 얕은 / 깊은 복사에 대해 설명합니다}
Shallow Copy : A에 대한 참조의 사본을 B로 만듭니다. A의 주소 사본이라고 생각하면됩니다. 따라서 A와 B의 주소는 동일합니다. 즉, 동일한 메모리 위치, 즉 데이터 내용을 가리 킵니다.
전체 복사 : A의 모든 구성원을 복사하고 B의 다른 위치에 메모리를 할당 한 다음 복사 된 구성원을 B에 할당하여 전체 복사를 수행합니다. 이런 식으로 A가 존재하지 않는 경우 B는 여전히 메모리에서 유효합니다. 사용할 올바른 용어는 복제입니다. 둘 다 완전히 동일하지만 다른 것 (즉, 메모리 공간에 두 개의 다른 하나의 저장 됨)을 알고 있습니다. 포함 / 제외 목록을 통해 전체 복사 중에서 선택할 속성을 선택할 수있는 복제 래퍼를 제공 할 수도 있습니다. 이것은 API를 만들 때 매우 일반적인 관행입니다.
관련된 이해 관계를 이해 한 경우 에만 얕은 복사를 선택할 수 있습니다 . C ++ 또는 C에서 처리 할 포인터가 엄청나게 많을 때 개체의 얕은 복사를 수행하는 것은 나쁜 생각입니다.
EXAMPLE_OF_DEEP COPY_ 예를 들어, 이미지 처리 및 인식을 수행 할 때 처리 영역에서 "무관하고 반복적 인 동작"을 가려야 합니다. 이미지 포인터를 사용하는 경우 해당 마스크 이미지를 저장할 수 있습니다. NOW ... 이미지의 얕은 복사본을 수행하면 포인터 참조가 스택에서 제거 될 때 참조와 해당하는 사본이 축소됩니다. 즉, 액세스 위반의 작동 오류가 발생합니다. 이 경우 필요한 복제하여 이미지의 깊은 사본입니다. 이렇게하면 나중에 필요할 때 마스크를 검색 할 수 있습니다.
EXAMPLE_OF_SHALLOW_COPY 저는 StackOverflow의 사용자에 비해 많은지 지식이 있습니다. 부분을 자유롭게 삭제하고 좋은 예를 찾을 수 있습니다. 하지만 프로그램이 무한한 시간 동안 실행될 수있는 것을 알고 있다고 생각합니다. 즉, 함수 호출로 스택을 통해 연속 "푸시 팝"작업을 수행합니다. (예 : C / C ++ 튜토리얼 자료) 괜찮습니다. 그러나 감시 및 감지 시스템이나 Sonar Tracking System과 같은 응용 프로그램을 실행하는 경우 조만간 프로그램을 죽일 수 있으므로 개체를 얕게 복사 할 수 있습니다.
char * Source = "Hello, world.";
char * ShallowCopy = Source;
char * DeepCopy = new char(strlen(Source)+1);
strcpy(DeepCopy,Source);
'ShallowCopy'는 'Source'와 동일한 메모리 위치를 가리 킵니다. 'DeepCopy'는 메모리의 다른 위치를 가리 키지 만 내용은 동일합니다.
얕은 복사 란 무엇입니까?
얕은 복사본은 개체의 비트 단위 복사본입니다. 원래 개체의 값과 정확히 일치하는 새 개체가 만들어집니다. 객체의 필드 중 하나가 다른 객체에 대한 참조 인 경우 참조 주소 만 복사됩니다. 즉, 메모리 주소 만 복사됩니다.
이 그림 에서이 MainObject1
필드가 field1
int 형, 그리고 ContainObject1
유형을 ContainObject
. 당신의 단순 복사본을 수행 할 때 MainObject1
, MainObject2
생성되는 field2
복사 된 값을 field1
여전히 포함하고 ContainObject1
있습니다. 이후 field1
는 그 값이 복사 되지만 field2
이후는 ContainedObject1
, 목적은 MainObject2
여전히 가리는 형태의 원시 ContainObject1
. 에 대한 변경 그래서 ContainObject1
에 MainObject1
반영 MainObject2
됩니다.
이제 이것이 얕은 카피라면 딥 카피가 무엇인지 볼까요?
딥 카피 란 무엇입니까?
전체 복사는 모든 필드를 복사하고 할당 메모리의 복사본을 만듭니다. 전체 복사는 개체가 참조하는 개체와 함께 복사 될 때 발생합니다.
이 그림에서 MainObject1은 필드가 field1
int 형, 그리고 ContainObject1
유형을 ContainObject
. 당신의 깊은 사본을 수행 할 때 MainObject1
, MainObject2
생성되는 field2
복사 된 값을 포함 field1
하고 ContainObject2
의 복사 된 값을 포함 ContainObject1
합니다. ContainObject1
에서 변경 한 사항은 MainObject1
반영되지 않습니다 MainObject2
.
프로그래밍 지향 프로그래밍에서 유형에는 멤버 필드 모음이 포함됩니다. 대신 필드는 값 또는 참조 (즉, 값에 대한 포인터)로 저장 될 수 있습니다.
단순 복사에서는 유형의 새 인스턴스가 작성되고 값이 새 인스턴스에 복사됩니다. 참조 포인터도 값처럼 복사됩니다. 따라서 참조는 원본 개체를 가리 킵니다. 참조에 의해 악성 멤버에 대한 모든 변경 사항은 참조 된 개체에 대한 복사본이 만들어지지 갑자기 기 원본과 복사본 모두에 나타납니다.
전체 복사에서 값으로 저장된 필드는 이전과 같이 복사는 참조로 복사 개체에 대한 포인터는 복사합니다. 대신 참조 된 개체로 전체 복사본이 만들어지고 새 개체에 대한 포인터가 저장됩니다. 참조 된 객체를 변경해도 수업의 다른 클래스에 영향을줍니다.
'ShallowCopy'는 'Source'와 동일한 메모리 위치를 가리 킵니다. 'DeepCopy'는 메모리의 다른 위치를 가리 키지 만 내용은 동일합니다.
얕은 복제 :
정의 : "개체의 얕은 복사본은 '주'개체를 복사하지만 내부 개체는 복사하지 않습니다." 사용자 지정 개체 (예 : Employee)에 기본 홈페이지 유형 변수 만있는 경우 Shallow Cloning을 사용합니다.
Employee e = new Employee(2, "john cena");
Employee e2=e.clone();
super.clone();
재정의 된 clone () 메서드로 반환 하면 작업이 끝납니다.
Deep Cloning :
정의 : "얕은 복사본과 달리 전체 복사본은 개체의 완전히 제거 된 인 복사본입니다."
직원이 다른 사용자 지정 개체를 보유하는 경우를 의미합니다.
Employee e = new Employee(2, "john cena", new Address(12, "West Newbury", "Massachusetts");
그런 다음 재정의 된 clone () 메서드 'Address'개체를 복제하는 코드를 작성해야합니다. 국제적인 주소 개체가 복제되지 않고 복제 된 직원 개체에서 주소 값을 설명 할 때 버그가 발생합니다. 이것은 원본도 반영합니다.
var source = { firstName="Jane", lastname="Jones" };
var shallow = ShallowCopyOf(source);
var deep = DeepCopyOf(source);
source.lastName = "Smith";
WriteLine(source.lastName); // prints Smith
WriteLine(shallow.lastName); // prints Smith
WriteLine(deep.lastName); // prints Jones
딥 카피
전체 복사는 모든 필드를 복사하고 할당 메모리의 복사본을 만듭니다. 전체 복사는 개체가 참조하는 개체와 함께 복사 될 때 발생합니다.
얕은 복사
얕은 복사본은 개체의 비트 단위 복사본입니다. 원래 개체의 값과 정확히 일치하는 새 개체가 만들어집니다. 개체의 필드 중 하나가 다른 개체에 대한 참조 인 경우 참조 주소 만 복사됩니다. 즉, 메모리 주소 만 복사됩니다.
얕은은 복사 -원본 및 얕은 복사 된 개체 내부의 참조 변수에는 공통 개체에 대한 참조가 있습니다.
전체 복사 -원본 및 전체 복사 된 개체 내부의 참조 변수는 다른 개체에 대한 참조를 사용 합니다.
복제는 항상 얕은 복사를 수행합니다.
public class Language implements Cloneable{
String name;
public Language(String name){
this.name=name;
}
public String getName() {
return name;
}
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
메인 클래스는
public static void main(String args[]) throws ClassNotFoundException, CloneNotSupportedException{
ArrayList<Language> list=new ArrayList<Language>();
list.add(new Language("C"));
list.add(new Language("JAVA"));
ArrayList<Language> shallow=(ArrayList<Language>) list.clone();
//We used here clone since this always shallow copied.
System.out.println(list==shallow);
for(int i=0;i<list.size();i++)
System.out.println(list.get(i)==shallow.get(i));//true
ArrayList<Language> deep=new ArrayList<Language>();
for(Language language:list){
deep.add((Language) language.clone());
}
System.out.println(list==deep);
for(int i=0;i<list.size();i++)
System.out.println(list.get(i)==deep.get(i));//false
}
위의 출력은 다음과 가변합니다.
거짓 참 참
거짓 거짓 거짓
원래 개체에서 변경된 사항은 깊은 개체가 아닌 얕은 개체에 반영됩니다.
list.get(0).name="ViSuaLBaSiC";
System.out.println(shallow.get(0).getName()+" "+deep.get(0).getName());
출력 -ViSuaLBaSiC C
공식적인 정의보다는 예를 들어보고 싶습니다.
var originalObject = {
a : 1,
b : 2,
c : 3,
};
이 코드는 얕은 사본을 보여줍니다 .
var copyObject1 = originalObject;
console.log(copyObject1.a); // it will print 1
console.log(originalObject.a); // it will also print 1
copyObject1.a = 4;
console.log(copyObject1.a); //now it will print 4
console.log(originalObject.a); // now it will also print 4
var copyObject2 = Object.assign({}, originalObject);
console.log(copyObject2.a); // it will print 1
console.log(originalObject.a); // it will also print 1
copyObject2.a = 4;
console.log(copyObject2.a); // now it will print 4
console.log(originalObject.a); // now it will print 1
이 코드는 딥 카피를 보여줍니다 .
var copyObject2 = Object.assign({}, originalObject);
console.log(copyObject2.a); // it will print 1
console.log(originalObject.a); // it will also print 1
copyObject2.a = 4;
console.log(copyObject2.a); // now it will print 4
console.log(originalObject.a); // !! now it will print 1 !!
struct sample
{
char * ptr;
}
void shallowcpy(sample & dest, sample & src)
{
dest.ptr=src.ptr;
}
void deepcpy(sample & dest, sample & src)
{
dest.ptr=malloc(strlen(src.ptr)+1);
memcpy(dest.ptr,src.ptr);
}
간단히 말해서 Shallow Copy는 Call By Reference와 유사하고 Deep Copy는 Call By Value와 유사합니다.
참조로 호출에서 함수의 형식 및 고유 한 메모리 위치와 값을 참조합니다.
Call By Value에서 함수의 형식 및 실제 변수는 모두 다른 메모리 위치를 참조하지만 동일한 값을가집니다.
arr1과 arr2라는 두 개의 배열이 상상해.
arr1 = arr2; //shallow copy
arr1 = arr2.clone(); //deep copy
단순 복사는 새로운 복합 객체를 생성하고 그 참조를 객체에 삽입합니다.
얕은 복사와 달리 deepcopy는 새로운 복합 개체를 생성하고 복합 개체의 원본 개체의 복사본도 삽입합니다.
예를 들어 보겠습니다.
import copy
x =[1,[2]]
y=copy.copy(x)
z= copy.deepcopy(x)
print(y is z)
위의 코드는 FALSE를 인쇄합니다.
방법을 보자.
원래 복합 개체 x=[1,[2]]
(개체 내부에 개체가 있기 때문에 합성이라고 함 (Inception))
이미지에서 볼 수 목록 안에 목록이 있습니다.
그런 다음을 사용하여 얕은 복사본을 만듭니다 y = copy.copy(x)
. 여기서는 그곳에서 새로운 복합 객체를 생성하지만 그 안에있는 객체를 생성합니다.
이미지에서 외부 목록에 대한 새 사본을 작성했습니다. 그러나 내부 목록은 원래 목록과 동일하게 유지됩니다.
이제 우리는 z = copy.deepcopy(x)
. 여기서는 그곳에서 할 일 외부 목록과 내부 목록에 대한 새 객체를 생성하는 것입니다. 아래 이미지와 같이 (빨간색 강조 표시).
마지막 코드는 False
y와 z가 같은 현상이 아니기 때문에 인쇄 합니다.
HTH.
단순 복사는 새 object-를 만든 다음 현재 object-의 non-정적 필드를 새 object-에 복사하는을 구석으로입니다. 필드가 값 유형 인 경우-> 필드의 비트 단위 복사가 수행됩니다. A에 대한 기준 입력 -> 참조 복사 언어 입력 ; 따라서 원본 개체와 해당 개체를 참조합니다.
전체 복사는 새 개체를 만든 다음 현재 개체의 비 정적 필드를 새 개체에 복사하는 것입니다. 필드가 값 유형 ->이면 필드의 비트 단위 복사가 수행됩니다. 필드가 참조 유형 인 경우 -> 참조 된 객체의 새 복사본이 수행됩니다. 복제 할 클래스는 [Serializable]로 표시되어야합니다.
[블로그]에서 발췌 : http://sickprogrammersarea.blogspot.in/2014/03/technical-interview-questions-on-c_6.html
전체 복사 에는 한 개체의 내용을 사용하여 동일한 클래스의 다른 인스턴스를 만드는 작업이 포함됩니다. 전체 복사에서 두 개체는 동일한 정보를 포함 할 수 있고 대상 개체에는 자체 버퍼와 리소스가 있습니다. 두 개체의 파괴는 나머지 개체에 영향을 미칠 수 있습니다. 오버로드 된 할당 연산자는 개체의 전체 복사본을 만듭니다.
얕은 복사 는 한 객체의 내용을 동일한 클래스의 다른 인스턴스로 복사하여 미러 이미지를 만드는 것을 포함합니다. 참조 및 내용의 공유 복사로 인해 두 개체는 예측할 수있는 다른 개체의 동일한 외부 포함됩니다.
설명 :
복사 생성 기능을 사용하여 멤버별로 데이터 값을 간단히 복사합니다. 이 복사 방법을 얕은 복사라고합니다. 객체가 내장되어 구성되고 포인터가없는 단순한 클래스 인 경우 허용됩니다. 이 함수는 값과 객체를 사용하며 그 동작은 얕은 복사로 변경되지 않습니다., 주소가 수신 값이 아닌 멤버 인 포인터의 주소 만 복사됩니다. 수업의 데이터 값이 함수에 의해 실수로 변경됩니다. 함수가 범위를 벗어나면 모든 데이터가 팝되는 복사본이 스택에서 발생합니다.
객체에 포인터가있는 경우 전체 복사를 실행해야합니다. 무료 저장소의 전체 복사를 사용하면 할당되고 할당 된 요소가 복사됩니다. 함수에서 반환되는 개체에 대해 전체 복사가 사용됩니다.
다른 답변에 더 추가 비용
- 유형의 Shallow Copy는 값 유형 기반 속성에 대한 값별 복사를 수행하고 참조 기반 속성에 대한 참조 별 복사를 수행합니다.
- 객체의 전체 복사는 값 유형 기반 속성에 대한 값별 복사를 수행하고 계층 구조 (참조 유형의) 깊은 참조 유형 기반 속성에 대한 값별 복사를 수행합니다.
얕은 복사는 새 참조를 생성하지 않지만 전체 복사는 새 참조를 생성합니다.
다음은 딥 카피와 얕은 카피를 설명하는 프로그램입니다.
public class DeepAndShollowCopy {
int id;
String name;
List<String> testlist = new ArrayList<>();
/*
// To performing Shallow Copy
// Note: Here we are not creating any references.
public DeepAndShollowCopy(int id, String name, List<String>testlist)
{
System.out.println("Shallow Copy for Object initialization");
this.id = id;
this.name = name;
this.testlist = testlist;
}
*/
// To performing Deep Copy
// Note: Here we are creating one references( Al arraylist object ).
public DeepAndShollowCopy(int id, String name, List<String> testlist) {
System.out.println("Deep Copy for Object initialization");
this.id = id;
this.name = name;
String item;
List<String> Al = new ArrayList<>();
Iterator<String> itr = testlist.iterator();
while (itr.hasNext()) {
item = itr.next();
Al.add(item);
}
this.testlist = Al;
}
public static void main(String[] args) {
List<String> list = new ArrayList<>();
list.add("Java");
list.add("Oracle");
list.add("C++");
DeepAndShollowCopy copy=new DeepAndShollowCopy(10,"Testing", list);
System.out.println(copy.toString());
}
@Override
public String toString() {
return "DeepAndShollowCopy [id=" + id + ", name=" + name + ", testlist=" + testlist + "]";
}
}
ararys 복사 :
array1 = array2는 배열을 참조하는 두 개의 변수를 생성합니다.
그러나이 예를 들어.
static void Main()
{
int[] arr1 = new int[] { 1, 2, 3, 4, 5 };
int[] arr2 = new int[] { 6, 7, 8, 9, 0 };
Console.WriteLine(arr1[2] + " " + arr2[2]);
arr2 = arr1;
Console.WriteLine(arr1[2] + " " + arr2[2]);
arr2 = (int[])arr1.Clone();
arr1[2] = 12;
Console.WriteLine(arr1[2] + " " + arr2[2]);
}
얕은 복제 는 복제 된 배열이 배열이 메모리 만 복사됨을 의미합니다.
배열에 값이 있으면 비용이 들게 보내 주시면 됩니다.
배열에 참조 유형이 포함 된 경우 참조 만 복사됩니다. 따라서 구성원이 객체를 참조하는 두 개의 배열이 있습니다 .
참조 유형이 복제되는 전체 복사본을 만들려면 배열을 반복하고 요소를 수동으로 복제해야합니다.
나는 다음 줄에서 이해하게 예.
얕은 복사는 객체 값 유형 (int, float, bool) 필드를 대상 객체에 복사하고 객체의 참조 유형 (문자열, 클래스 등)은 대상 객체의 참조 로 복사 됩니다. 이 대상에서 참조는 소스 개체의 메모리 위치를 가리 유형입니다.
전체 복사는 객체의 값과 참조 유형을 대상의 완전히 새로운 사본으로 복사합니다. 이는 값 유형과 참조 유형 모두에 새 메모리 위치가 할당됨을 의미합니다.
위의 모든 정의에 더하고 가장 일반적으로 사용되는 깊은 복사는 클래스의 복사 생성자 (또는 오버로딩 할당 연산자)에 있습니다.
Shallow copy->는 복사 생성시 제공되지 않는 경우입니다. 여기에서는 모든 멤버가 복사되는 클래스의 모든 멤버가 복사됩니다.
Deep copy->는 클래스에서 복사 생성자 또는 오버로드 할당을 구현하고 클래스의 모든 멤버를 복사 할 수 있도록 결정한 경우입니다.
MyClass& MyClass(const MyClass& obj) // copy constructor for MyClass
{
// write your code, to copy all the members and return the new object
}
MyClass& operator=(const MyClass& obj) // overloading assignment operator,
{
// write your code, to copy all the members and return the new object
}
복사 생성자는 이전에 생성 된 동일한 클래스의 객체로 새 객체를 초기화하는 데 사용됩니다. 기본적으로 컴파일러는 얕은 복사본을 작성했습니다. 얕은 복사는 동적 메모리 할당이 관련되지 않은 경우 잘 작동합니다. 동적 메모리 할당이 관련 널 두 객체가 힙의 동일한 메모리 위치를 가리 키기 때문입니다. 따라서 두 가지 모두 고유 한 속성 사본을 갖도록 딥 복사를 작성했습니다. 기억에. 전체 예제와 설명이 포함 된 세부 정보를 기사를 참조하십시오 C ++ 생성자 기사를 참조하십시오 .
'ProgramingTip' 카테고리의 다른 글
Java에서 객체를 어떻게 복사합니까? (0) | 2020.09.29 |
---|---|
npm WARN package.json : 저장소 필드 없음 (0) | 2020.09.29 |
딜레마 : 프래그먼트와 활동을 사용하는 경우 : (0) | 2020.09.29 |
목록 이해력에 권한이 있습니까? (0) | 2020.09.29 |
Visual Studio 솔루션에서 코드 줄을 어떻게 계산합니까? (0) | 2020.09.29 |