Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/268.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C#(或java)中的clone方法是否在内部使用new操作符?_C#_Java - Fatal编程技术网

C#(或java)中的clone方法是否在内部使用new操作符?

C#(或java)中的clone方法是否在内部使用new操作符?,c#,java,C#,Java,这实际上是一个面试问题,关于创建类实例的不同方法。新的和反思是众所周知的。但是clone()也会创建对象。但它是否在内部使用new关键字来创建它?这是在c#的上下文中提出的,但也希望了解java。通常,Clone实现将使用受保护的MemberwiseClone方法创建基本对象,然后根据需要调整字段(例如,深度复制列表,而不是让两个实例引用同一个) 不过,并没有什么规定他们必须这样做——他们可以调用构造函数来生成对象,然后根据需要设置字段 在内部,MemberwiseClone只是(我想-这一点不

这实际上是一个面试问题,关于创建类实例的不同方法。新的和反思是众所周知的。但是clone()也会创建对象。但它是否在内部使用new关键字来创建它?这是在c#的上下文中提出的,但也希望了解java。

通常,
Clone
实现将使用受保护的
MemberwiseClone
方法创建基本对象,然后根据需要调整字段(例如,深度复制列表,而不是让两个实例引用同一个)

不过,并没有什么规定他们必须这样做——他们可以调用构造函数来生成对象,然后根据需要设置字段


在内部,
MemberwiseClone
只是(我想-这一点不确定)对象所占用内存的直接转录,并且不以任何方式涉及构造函数。

对于Java,答案是“否”。有关算法的文档非常详细:

此方法创建此对象类的新实例,并使用此对象对应字段的内容初始化其所有字段,就像通过赋值一样;字段的内容本身不是克隆的。因此,此方法执行此对象的“浅拷贝”,而不是“深拷贝”操作

您也可以在实践中轻松地检查它。

Clone()
在C中是通过实现
ICloneable
接口来实现的。你怎么做完全取决于你自己

比如说,

  • 不可变对象,如
    String
    RuntimeType
    只返回
    this
    (即它们自己)
  • 一些标准的
    Clone
    调用(即
    System.Array
    System.Delegate
    返回
    Object.MemberwiseClone()
    ,它执行CLR调用来创建浅层副本。我想这类似于
    new()
    (它将创建新引用等),但我不相信(尽管没有程序集来确认)它将调用一个构造函数
  • 其他对象倾向于实现自己的
    Clone()
    过程
示例
System.Version

public object Clone()
{
    Version version = new Version();
    version._Major = this._Major;
    version._Minor = this._Minor;
    version._Build = this._Build;
    version._Revision = this._Revision;
    return version;
}

好的,大家的共识是,因为new涉及构造函数,而clone不涉及调用构造函数(除非我们提出克隆的实现),所以clone在内部不使用new。

对于C#很容易测试object.MemberwiseClone在构造函数方面的功能:

class Program
{
    class A : ICloneable
    {
        public int X = 2;
        public A()
        {
            Console.WriteLine("hiya");
            X = 1;
        }

        public object Clone()
        {
            A a = MemberwiseClone() as A;

            return a;
        }
    }

    static void Main(string[] args)
    {
        A a = new A();
        a.X = 3;
        A b = a.Clone() as A;
    }
}
在构造函数中放置一个断点。上面的程序只调用一次断点。如果考虑到它,基类中的克隆无法调用构造函数:

  • 它将要建造什么?它 能够反映并获得最多 派生类型
  • 但是如果是那种类型呢 没有公共的无参数 建造师
  • 它能调用一个私有函数吗 或受保护的构造函数和 要初始化的对象 没错

MemberWiseClone的默认实现必须依赖于较低级别的类型初始化,而不是构造。替代方案将难以实现,难以理解,并且是难以发现的bug的来源。

在Java中,当调用
clone()时
惯例是,返回的对象应该通过调用
super.clone()获得
。最终,这将到达的方法。此时,行为由接口决定:如果类实现,则方法返回对象的逐字段副本;否则将抛出。因此
clone()
在不调用构造函数的情况下创建对象,得到的是对象的副本


作为一个旁注,Java的
clone
是,Joshua Bloch建议提供一个复制构造函数复制工厂。这将在有效的Java第二版中讨论。

您省略了该段的开头:“类对象的方法clone执行特定的克隆操作”。因此您的引号仅适用于java.lang.Object中的实现。派生类中的重写可以做什么完全取决于它们:它们通常调用super.clone()然后对结果执行其他操作,但没有强制执行的内容,也没有需要的语句。@EJP您是对的,但也有一个约定:按照约定,返回的对象应该通过调用super.clone获得。因此,您描述的内容是可能的,尽管它被认为是“坏java”。