深拷贝,浅拷贝,克隆 [英] Deep copy, shallow copy, clone

查看:112
本文介绍了深拷贝,浅拷贝,克隆的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我需要澄清深拷贝,浅拷贝和克隆在Java中的区别

解决方案

不幸的是,浅拷贝,深拷贝和克隆都是相当不明确的术语。






在Java环境中,我们首先需要区分复制值和复制对象。

  int a = 1; 
int b = a; //复制值
int [] s = new int [] {42};
int [] t = s; //复制一个值(上面数组的对象引用)

StringBuffer sb = new StringBuffer(嗨妈妈);
//复制一个对象。
StringBuffer sb2 = new StringBuffer(sb);

简而言之,对类型为引用类型的变量的引用的赋值是复制值其中值是对象引用。要复制一个对象,需要使用 new ,无论是明确地还是在幕后。






现在用于浅与深复制对象。浅复制通常表示仅复制对象的一个​​级别,而深度复制通常表示复制多个级别。问题在于决定一个级别的含义。考虑一下:

  public class Example {
public int foo;
public int [] bar;
public Example(){};
public Example(int foo,int [] bar){this.foo = foo; this.bar = bar; };
}

示例eg1 = new示例(1,new int [] {1,2});
示例eg2 = ...

正常的解释是浅副本 eg1 将是一个新的示例对象,其 foo 等于1并且其 bar 字段引用与原始字段相同的数组;例如。

 示例eg2 = new示例(eg1.foo,eg1.bar); 

深层副本的正常解释eg1 将是一个新的示例对象,其 foo 等于1且其字段是指原始数组的副本;例如。

 示例eg2 = new示例(eg1.foo,Arrays.copy(eg1.bar)); 

(来自C / C ++背景的人可能会说出一个参考赋值产生一个浅的副本。但是,这不是我们通常在Java上下文中浅层复制的意思...)



还存在两个不确定的问题/领域: / p>


  • 深度有多深?它停在两个级别吗?三个级别?它是否意味着连接对象的整个图形?


  • 封装数据类型如何;例如一个字符串? String实际上不仅仅是一个对象。实际上,它是一个带有一些标量字段的对象,以及对一个字符数组的引用。但是,API完全隐藏了字符数组。因此,当我们谈论复制字符串时,将其称为浅副本还是深度副本是否有意义?或者我们应该把它称为副本?







最后,克隆。克隆是一种存在于所有类(和数组)上的方法,通常被认为是生成目标对象的副本。但是:




  • 此方法的规范故意没有说明这是浅拷贝还是深拷贝(假设这是有意义的区别)。


  • 事实上,规范甚至没有具体说明克隆产生了一个新对象。




这是 javadoc 说:


创建并返回一份副本复制的确切含义可能取决于对象的类。一般意图是,对于任何对象x,表达式 x.clone()!= x 将为true,表达式 x.clone()。getClass()== x.getClass()将为true,但这些并非绝对要求虽然通常情况下 x.clone()。equals(x)将为真,但这不是绝对的要求。




注意,这就是说克隆可能在某个极端可能是目标对象,而在另一个极端,克隆可能不是等于原件。这假设甚至支持克隆。



简而言之,克隆可能意味着每个Java类都有不同的东西。



< hr>

有些人认为(如@supercat在评论中所做的那样)Java clone()方法已被破坏。但我认为正确的结论是克隆的概念在OO的背景下被打破。 AFAIK,不可能在所有对象类型中开发统一的克隆模型。


I need clarification on the differences between deep copy, shallow copy, and clone in Java

解决方案

Unfortunately, "shallow copy", "deep copy" and "clone" are all rather ill-defined terms.


In the Java context, we first need to make a distinction between "copying a value" and "copying an object".

int a = 1;
int b = a;     // copying a value
int[] s = new int[]{42};
int[] t = s;   // copying a value (the object reference for the array above)

StringBuffer sb = new StringBuffer("Hi mom");
               // copying an object.
StringBuffer sb2 = new StringBuffer(sb);

In short, an assignment of a reference to a variable whose type is a reference type is "copying a value" where the value is the object reference. To copy an object, something needs to use new, either explicitly or under the hood.


Now for "shallow" versus "deep" copying of objects. Shallow copying generally means copying only one level of an object, while deep copying generally means copying more than one level. The problem is in deciding what we mean by a level. Consider this:

public class Example {
    public int foo;
    public int[] bar;
    public Example() { };
    public Example(int foo, int[] bar) { this.foo = foo; this.bar = bar; };
}

Example eg1 = new Example(1, new int[]{1, 2});
Example eg2 = ... 

The normal interpretation is that a "shallow" copy of eg1 would be a new Example object whose foo equals 1 and whose bar field refers to the same array as in the original; e.g.

Example eg2 = new Example(eg1.foo, eg1.bar);

The normal interpretation of a "deep" copy of eg1 would be a new Example object whose foo equals 1 and whose bar field refers to a copy of the original array; e.g.

Example eg2 = new Example(eg1.foo, Arrays.copy(eg1.bar));

(People coming from a C / C++ background might say that a reference assignment produces a shallow copy. However, that's not what we normally mean by shallow copying in the Java context ...)

Two more questions / areas of uncertainty exist:

  • How deep is deep? Does it stop at two levels? Three levels? Does it mean the whole graph of connected objects?

  • What about encapsulated data types; e.g. a String? A String is actually not just one object. In fact, it is an "object" with some scalar fields, and a reference to an array of characters. However, the array of characters is completely hidden by the API. So, when we talk about copying a String, does it make sense to call it a "shallow" copy or a "deep" copy? Or should we just call it a copy?


Finally, clone. Clone is a method that exists on all classes (and arrays) that is generally thought to produce a copy of the target object. However:

  • The specification of this method deliberately does not say whether this is a shallow or deep copy (assuming that is a meaningful distinction).

  • In fact, the specification does not even specifically state that clone produces a new object.

Here's what the javadoc says:

"Creates and returns a copy of this object. The precise meaning of "copy" may depend on the class of the object. The general intent is that, for any object x, the expression x.clone() != x will be true, and that the expression x.clone().getClass() == x.getClass() will be true, but these are not absolute requirements. While it is typically the case that x.clone().equals(x) will be true, this is not an absolute requirement."

Note, that this is saying that at one extreme the clone might be the target object, and at the other extreme the clone might not equal the original. And this assumes that clone is even supported.

In short, clone potentially means something different for every Java class.


Some people argue (as @supercat does in comments) that the Java clone() method is broken. But I think the correct conclusion is that the concept of clone is broken in the context of OO. AFAIK, it is impossible to develop a unified model of cloning that is consistent and usable across all object types.

这篇关于深拷贝,浅拷贝,克隆的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆