提问人:Cuga 提问时间:5/6/2009 最后编辑:T.J. CrowderCuga 更新时间:1/19/2019 访问量:35020
为什么 Java 没有复制构造函数?
Why doesn't Java have a copy constructor?
答:
猜猜他们认为你可以做一个 clone() 方法吗?
我认为这个问题的答案非常有趣。
首先,我相信在 Java 中,所有对象都在堆上,虽然你没有指针,但你确实有“引用”。引用具有复制符号,java 内部跟踪引用计数,以便其垃圾收集器知道哪些是安全的。
由于您只能通过可复制的引用访问对象,因此需要复制对象的实际次数大大减少(例如,在 C++ 中,仅将对象传递给函数(按值)会导致复制构造新对象,而在 Java 中仅传递对对象的引用)。设计人员可能认为 clone() 足以满足剩余的用途。
评论
Object.clone()
这只是我的意见(我相信有一个合理的答案)
C++ 中的复制构造函数主要在按值发送或返回类实例时有用,因为这是透明激活复制构造函数的时候。
由于在 Java 中,所有内容都是通过引用返回的,并且 VM 面向动态分配,因此实际上没有理由解释复制构造函数的复杂性。
此外,由于一切都是通过引用进行的,因此开发人员通常必须提供自己的实现和如何克隆字段的决定。
确实如此。当浅拷贝没问题时,你有[clone()](http://java.sun.com/j2se/1.4.2/docs/api/java/lang/Object.html#clone()),当它们不行时,你必须像C++一样实现深拷贝。
唯一的实质性区别是它是一种工厂方法,而不是构造函数,但就灵活性和可测试性而言,这可能是一件好事。
我不太喜欢C++程序员,但我似乎记得关于“三个朋友”的规则 - 复制构造函数,赋值运算符和析构函数。如果你有一个,那么你可能需要这三个。
因此,也许语言中没有析构函数,他们不想包含复制构造函数?只是一个猜测。
评论
为什么[复制构造函数]在C++而不是Java中工作?
复制构造函数是一个基本的 C++的一部分,因为它会自动 创建对象的本地副本。还 上面的例子证明它确实如此 不适用于 Java。为什么?在 Java 中 我们操纵的一切都是一个 句柄,而在 C++ 中您可以拥有 类似句柄的实体,您还可以 直接传递对象。 这就是 C++ 复制构造函数的内容 适用于:当您想采取 对象并按值传入,因此 复制对象。所以它有效 在C++中很好,但你应该保持 请注意,这个方案在 Java 中失败了, 所以不要使用它。
(我建议阅读整个页面 - 实际上,从这里开始。
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 中,它只是复制引用。对象的状态不会被复制,因此隐式调用复制构造函数是没有意义的。
这就是它的全部内容。
评论
public class Blah { private A foo; //A is some class public Blah(Blah b) { foo = b.foo; } // this would not work would it ? }
public Blah(Blah b) { foo = new A(b.foo); }
Java 有 copy 构造函数
注意:代替 demo d2=new demo(d1),你可以编写 demo d2=d1
主要区别 b/w 两个
demo d2=new demo(d1) 表示新对象被创建,它是
分配的内存 但是
demo d2=d1 意味着只创建了引用变量
它使用对象 D1 的相同内存地址,因此未分配 D2
分离的内存。
复制构造函数的语法:
见下文 第一个示例 复制构造函数非常简单 :)) classname(int datafield)
//简单构造函数
{
this.datafield=datafield;
}
classname(classname object)
{ datafield=
object.datafield;//参见以下示例
}
现在用于调用
{
类名 obj=new classname();
classname anotherObject=obj;//或 classname anotherObject=new classname(obj)
}
class demo { private int length; private int breadth; private int radius; demo(int x,int y) { length=x; breadth=y; } int area() { return length*breadth; } //Copy Constructor demo(demo obj) { length=obj.length; breadth=obj.breadth; } public static void main(String args[]) { demo d1=new demo(5,6); demo d2=new demo(d1);//Invokes Copy Constructure System.out.println("Area for d1 object="+d1.area()); System.out.println("Area for d2 object="+d2.area()); } }
嗯,它可以。它只是没有隐式创建。如果我不得不猜测,这可能与 Java 对象总是堆分配的事实有关。
在 C++ 中,默认复制构造函数是成员级浅表复制。如果一个类拥有堆上分配的内存(通过原始指针),这将导致副本与原始副本共享内部,这不是你想要的。
想象一下,Java 有这种行为。任何具有对象字段的类(阅读:基本上是所有字段)都会有错误的行为,您需要自己重写它。在99%的情况下,你没有给任何人带来任何麻烦。此外,您刚刚为自己创建了一个微妙的陷阱 - 想象一下,您不小心忘记覆盖默认的复制构造函数。如果它是默认生成的,并且您尝试使用它,编译器根本不会抱怨,但您的程序在运行时会行为不端。
即使他们制作了一个执行深度复制的默认复制构造函数,我也不确定这是否特别有用。无论如何,您不仅倾向于在 Java 中执行比 C++ 更少的副本,而且您并不总是想要深度复制字段。
您只拥有的对象,以及由于需要它们而持有引用但不负责的对象是相同的 - 只是字段。所有权和借款不是一流的概念。对于您拥有的对象,您需要深度复制它们(除非它们是不可变的,在这种情况下,您不应该打扰),对于您只持有引用的对象,您需要复制引用。
我认为,一个只是盲目地深度复制所有内容的复制构造函数也不适合许多类。不过,默认情况下肯定不仅仅是浅层复制。
上一个:如何使此 C++ 对象不可复制?
下一个:复制构造函数和赋值运算符
评论