深度复制和浅复制的区别是什么?
当前回答
浅拷贝不会创建新的引用,但深拷贝会创建新的引用。
下面是程序解释的深拷贝和浅拷贝。
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 + "]";
}
}
其他回答
浅复制-原始和浅复制对象中的引用变量引用公共对象。
深度复制-原始和深度复制对象中的引用变量引用不同的对象。
克隆总是做浅拷贝。
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
广度vs深度;从引用树的角度考虑,将对象作为根节点。
浅:
变量A和B指的是不同的内存区域,当B被分配给A时,这两个变量指的是相同的内存区域。后来对其中一个内容的修改立即反映在另一个的内容中,因为它们共享内容。
深:
变量A和B指的是不同的内存区域,当B被分配给A时,A所指向的内存区域中的值被复制到B所指向的内存区域。后来对其中一项内容的修改仍为A或B所独有;内容不共享。
简而言之,这取决于什么指向什么。在浅拷贝中,对象B指向对象a在内存中的位置。在深度复制中,对象A的内存位置中的所有东西都被复制到对象B的内存位置。
这篇wiki文章有一个很好的图表。
http://en.wikipedia.org/wiki/Object_copy
{想象两个对象:相同类型_t的A和B(相对于c++),你正在考虑将A浅/深复制到B}
浅拷贝: 简单地将a的引用复制到b中,把它看作是a的地址的副本。 因此,A和B的地址将是相同的,即它们将指向相同的内存位置,即数据内容。
Deep copy: Simply makes a copy of all the members of A, allocates memory in a different location for B and then assigns the copied members to B to achieve deep copy. In this way, if A becomes non-existant B is still valid in the memory. The correct term to use would be cloning, where you know that they both are totally the same, but yet different (i.e. stored as two different entities in the memory space). You can also provide your clone wrapper where you can decide via inclusion/exclusion list which properties to select during deep copy. This is quite a common practice when you create APIs.
只有当你了解其中的利害关系时,你才可以选择做浅拷贝。当你在c++或C中有大量的指针要处理时,做一个对象的浅拷贝真的是一个坏主意。
EXAMPLE_OF_DEEP COPY_ An example is, when you are trying to do image processing and object recognition you need to mask "Irrelevant and Repetitive Motion" out of your processing areas. If you are using image pointers, then you might have the specification to save those mask images. NOW... if you do a shallow copy of the image, when the pointer references are KILLED from the stack, you lost the reference and its copy i.e. there will be a runtime error of access violation at some point. In this case, what you need is a deep copy of your image by CLONING it. In this way you can retrieve the masks in case you need them in the future.
EXAMPLE_OF_SHALLOW_COPY I am not extremely knowledgeable compared to the users in StackOverflow so feel free to delete this part and put a good example if you can clarify. But I really think it is not a good idea to do shallow copy if you know that your program is gonna run for an infinite period of time i.e. continuous "push-pop" operation over the stack with function calls. If you are demonstrating something to an amateur or novice person (e.g. C/C++ tutorial stuff) then it is probably okay. But if you are running an application such as surveillance and detection system, or Sonar Tracking System, you are not supposed to keep shallow copying your objects around because it will kill your program sooner or later.
为了避免混淆浅复制和简单地为list分配一个新变量名,再添加一点。
“假设我们有:
x = [
[1,2,3],
[4,5,6],
]
这个语句创建了3个列表:2个内部列表和一个外部列表。然后,外部列表的引用在名称x下可用
y = x
没有数据被复制。我们在内存的某个地方仍然有相同的3个列表。所有这一切所做的是使外部列表在名称y下可用,除了它之前的名称x
y = list(x)
or
y = x[:]
这将创建一个与x内容相同的新列表。列表x包含对两个内部列表的引用,因此新列表也将包含对这两个内部列表的引用。只复制了一个列表——外层列表。 现在内存中有4个列表,两个内部列表,一个外部列表,以及外部列表的副本。原始外部列表的名称为x,新的外部列表的名称为y。
内部列表没有被复制!此时,您可以从x或y访问和编辑内部列表!
如果你有一个二维(或更高)的列表,或者任何类型的嵌套数据结构,并且你想对所有内容进行完整复制,那么你想在复制模块中使用deepcopy()函数。你的解决方案也适用于2-D列表,迭代外部列表中的项目,并对每个项目进行复制,然后为所有内部副本构建一个新的外部列表。”
来源:https://www.reddit.com/r/learnpython/comments/1afldr/why_is_copying_a_list_so_damn_difficult_in_python/