70

为什么 Java 不支持 C++ 中的复制构造函数?

4

9 回答 9

134

Java 可以。它们只是不像在 C++ 中那样被隐式调用,我怀疑这是你真正的问题。

首先,复制构造函数无非是:

public class Blah {
  private int foo;

  public Blah() { } // public no-args constructor
  public Blah(Blah b) { foo = b.foo; }  // copy constructor
}

现在 C++ 将使用如下语句隐式调用复制构造函数:

Blah b2 = b1;

在该实例中进行克隆/复制在 Java 中根本没有意义,因为所有 b1 和 b2 都是引用,而不是像在 C++ 中那样的值对象。在 C++ 中,该语句会复制对象的状态。在 Java 中,它只是复制引用。对象的状态不会被复制,因此隐式调用复制构造函数是没有意义的。

这就是它的全部。

于 2009-05-06T02:50:01.177 回答
14

布鲁斯埃克尔

为什么 [复制构造函数] 在 C++ 而不是 Java 中工作?

复制构造函数是 C++ 的基本部分,因为它会自动生成对象的本地副本。然而上面的例子证明它不适用于 Java。为什么?在 Java 中,我们操作的一切都是句柄,而在 C++ 中,您可以拥有类似句柄的实体,也可以直接传递对象。这就是 C++ 复制构造函数的用途:当您想要获取一个对象并按值传递它时,从而复制该对象。所以它在 C++ 中运行良好,但你应该记住,这个方案在 Java 中失败,所以不要使用它。

(我建议阅读整个页面——实际上,从这里开始。)

于 2009-05-06T02:48:11.057 回答
10

我认为这个问题的答案非常有趣。

一方面,我相信在 Java 中所有对象都在堆上,虽然你没有指针,但你确实有“引用”。引用具有复制语义,Java 在内部跟踪引用计数,以便其垃圾收集器知道可以安全地删除什么。

由于您仅通过可复制引用访问对象,因此需要复制对象的实际次数大大减少(例如,在 C++ 中,仅将对象传递给函数(按值)导致新对象被复制构造,在 Java 中仅传递对对象的引用)。设计者可能认为 clone() 足以满足其余用途。

 

于 2009-05-06T02:45:49.063 回答
2

这只是我的意见(我相信有一个合理的答案)

当您按值发送或返回类的实例时,C++ 中的复制构造函数主要有用,因为此时复制构造函数被透明地激活。

由于在 Java 中所有内容都是通过引用返回的,并且 VM 面向动态分配,因此复制构造函数的复杂性确实没有理由。

此外,由于一切都是参考,开发人员通常必须提供他们自己的实现并决定如何克隆字段。

于 2009-05-06T02:46:21.077 回答
1

猜猜他们认为你可以只创建一个 clone() 方法?

于 2009-05-06T02:39:00.873 回答
0

确实如此。当浅拷贝没问题时,你有 [clone()]( http://java.sun.com/j2se/1.4.2/docs/api/java/lang/Object.html#clone())并且当它们不是你必须像 C++ 一样实现深拷贝。

唯一的实质性区别是它是工厂方法而不是构造函数,但就灵活性和可测试性而言,这可能是一件好事。

于 2009-05-06T02:46:32.463 回答
0

我不是一个 C++ 程序员,但我似乎确实记得关于“三个朋友”的规则——复制构造函数、赋值运算符和析构函数。如果你有一个,那么你可能需要所有三个。

所以也许语言中没有析构函数,他们不想包含复制构造函数?只是一个猜测。

于 2009-05-06T02:47:52.023 回答
0

嗯,它可以。它只是不会被隐式创建。如果我不得不猜测,这可能与 Java 对象总是堆分配的事实有关。

在 C++ 中,默认的复制构造函数是按成员的浅拷贝。如果一个类拥有在堆上分配的内存(通过原始指针),这将导致副本与原始类共享内部,这不是您想要的。

想象一下Java有这种行为。任何具有对象字段的类(阅读:基本上所有对象)都会有错误的行为,您需要自己覆盖它。对于 99% 的情况,您没有为任何人省去任何麻烦。此外,您刚刚为自己创建了一个微妙的陷阱——假设您不小心忘记了覆盖默认的复制构造函数。如果它是默认生成的,并且您尝试使用它,编译器根本不会抱怨,但是您的程序会在运行时出现异常。

即使他们创建了一个执行深层复制的默认复制构造函数,我也不确定这是否特别有用。无论如何,您不仅倾向于在 Java 中执行比 C++ 更少的副本,而且您并不总是希望对字段进行深度复制。

您刚刚拥有的对象和您因为需要它们而持有引用但不负责的对象是相同的 - 只是字段。所有权和借款不是一流的概念。对于您拥有的对象,您需要深度复制它们(除非它们是不可变的,在这种情况下您不应该打扰),而对于您只持有引用的对象,您想要复制引用。

我会争辩说,只是盲目地深度复制所有内容的复制构造函数也不适合许多类。当然,默认情况下不仅仅是浅拷贝。

于 2016-08-29T18:26:03.863 回答
-1

Java复制构造函数
注意:不是demo d2=new demo(d1),你可以写demo d2=d1
主要区别 b/w 两个
demo d2=new demo(d1)表示创建新对象并分配内存 但是
demo d2=d1 意味着只创建引用变量,它使用对象d1的相同内存地址,因此d2没有分配单独的内存。

拷贝构造函数的语法:
见下例第一个拷贝构造函数很简单:))
classname(int datafield) //Simple Constructor
{
this.datafield=datafield;
}

classname(classname object)
{
datafield=object.datafield;//见下例
}
现在调用
{

类名 obj=新类名();

classname anotherObject=obj;//或类名 anotherObject=new classname(obj)

}

 课堂演示
{
    私有 int 长度;

    私有宽度;

    私有int半径;

    演示(int x,int y)

    {
        长度=x;
        宽度=y;
    }
    整数区域()
    {
        返回长度*宽度;
    }

    //复制构造函数
    演示(演示对象)
    {
        长度=obj.长度;
        宽度=obj.宽度;
    }


    公共静态无效主(字符串参数 [])
    {
        演示 d1=新演示(5,6);
        demo d2=new demo(d1);//调用复制结构
        System.out.println("d1 对象的区域="+d1.area());
        System.out.println("d2 对象的区域="+d2.area());

    }
}

于 2013-07-07T22:31:33.703 回答