为什么我们需要复制构造函数以及何时应该在java中使用复制构造函数
我正在浏览Copy Constructors,我已经浏览了堆栈中的链接和其他链接。 但我不清楚以下几点。
- 为什么我们需要一个Copy Constructor
- 我们何时需要复制构造函数
我的意思是我们需要使用Copy Constructor的确切情况或场景是什么。 有人可以用一个例子解释或指出链接,这样我就可以明确地理解它们。
以下是我经历的链接,以了解什么是复制构造函数。
http://www.programmerinterview.com/index.php/java-questions/how-copy-constructors-work/
https://deepeshdarshan.wordpress.com/2013/12/05/copy-constructors-in-java/
第二个链接解释了“为什么”和“在哪里”使用复制构造函数。 但我仍然不清楚它。
下面是我的Employee.java类
package com.test; /** * @author avinashd * */ public class Employee { private String rollNo; private String name; //constructor public Employee(String rollNo, String name){ this.rollNo = rollNo; this.name = name; } //copy constructor public Employee(Employee employee){ this.rollNo = employee.rollNo; this.name = employee.name; } public String getRollNo() { return rollNo; } public void setRollNo(String rollNo) { this.rollNo = rollNo; } public String getName() { return name; } public void setName(String name) { this.name = name; } }
复制构造函数用于创建具有相同现有对象值的对象的精确副本。
比方说,我们有一个Employee,其值为rollNo: 1
和name: avinash
。 复制构造函数将创建一个类似的对象,其值为rollNo: 1
和name: avinash
。 但两者都是2个不同的对象,对on对象的值的更改不会影响另一个对象。
这里的问题是
当我们有一个构造函数,如
public Employee(String rollNo, String name){ this.rollNo = rollNo; this.name = name; }
创建一个对象。 我们可以调用相同的构造函数来创建另一个对象。 但是为什么我们需要调用copy构造函数。什么时候需要调用它? 请解释
使用复制构造函数而不是传递所有参数的构造函数有两个很好的理由:
- 当你有一个具有许多属性的复杂对象时,使用复制构造函数要简单得多
- 如果向类中添加属性,则只需更改复制构造函数即可将此新属性考虑在内,而不是更改其他构造函数的每个出现位置
按照惯例,复制构造函数应该提供对象的深层副本。 正如其他答案已经提到的,复制构造函数提供的主要便利是当对象变得太复杂时。 请注意, java.lang.Cloneable
提供了(几乎)类似的声明。
但是,在Cloneable
接口上使用复制构造函数有许多优点。
-
Cloneable
作为接口实际上不提供任何方法。 为了使它有效,您仍然需要覆盖java.lang.Object
的clone
方法。 这对于接口来说是非常违反直觉的。 -
clone
返回一个Object
。 为了它的任何用途,你仍然需要进行类型转换。 这很尴尬,可能导致运行时错误。 -
clone
方法记录很少。 对于clone
,如果你有最终字段指向可变对象,事情就会搞砸。 -
最重要的是,复制构造函数可以接收和深度复制子类的实例。 IMO,这是复制构造者真正发挥作用的地方。
有更多的优点(参见Joshua Bloch的Effective Java 2e ),但这些是我发现的与我迄今为止所做的工作最相关的要点。
[1] Java语言中没有任何内容实际上为深度复制提供了默认构造。 最多,对象可以告诉程序员可以通过实现Cloneable
或提供复制构造函数来深度复制它们。
如果您希望另一个Employee
实例具有与您已有的完全相同的值,该怎么办?
你会打电话吗?
setName(oldEmployee.getName()).. setRollNumber(oldEmployee.getRollNumber()).. etc..
而不是这样做,使用它
Employee copyOfEmployeeOne=new Employee(employeeOneInstance); // no need of a sequence of setters..
另一种情况是存储对象“历史”值。
所以你有单个对象,但每当你改变它的状态时,你想将它添加到ArrayList
或任何最适合你的数据结构,而不是手动复制数据,你只需在进一步修改之前使用“复制构造函数”。
复制构造函数比Object.clone()方法具有许多优点,其中一些如下
- 复制构造函数优于Object.clone(),因为它们
- 不要强迫我们实现任何接口或抛出任何exception。
- 不要求任何演员阵容。
- 不要求我们依赖于未知的对象创建机制。
- 不要求父类遵守任何合同或实施任何内容。
- 允许我们修改最终字段。
- 让我们完全控制对象创建,我们可以在其中编写初始化逻辑。
阅读有关Java克隆的更多信息- 复制构造函数与克隆
通过Copy构造函数我们可以使用诸如实现Cloneable接口和覆盖克隆方法之类的复杂内容来进行克隆。 我们也不需要特别担心深度克隆。
但需要注意的是:
1.当我们实现Cloneable时,对其他类/用户来说,这个类的对象可以是可克隆的。 除此之外,其他类可能没有关于cloneable的显式信息。
2.如果我们将复制构造函数设置为私有,那么我们可以限制克隆此类的对象。 然后,此复制构造函数只能用于在本地到类中初始化新创建的对象,而不是用于在其他类中进行克隆。
3.当你不想让你的类可以克隆时,如果你有一个带有访问说明符public的写复制构造函数,那么它会导致不安全,其他类可以创建你的类的对象。
复制构造函数实现了浅层和深层克隆机制,但使用复制构造函数而不是克隆(使用Cloneable接口)的主要优点是:
- 在使用Object.clone()方法时,我们不需要任何类型的shell。
- 我们将能够修改最终字段以进行复制,这与我们在Object.clone()机制的情况下无法修改或访问最终字段不同。
- 它允许我们完全控制对象创建,我们可以在其中编写初始化逻辑。
- 如果我们想要克隆包含其他依赖类的引用变量的类的对象,我们不需要实现类的克隆方法。 只需初始化我们的复制构造函数,我们就可以实现这一点。
与C ++不同,Java不提供直接复制构造函数。 但是,可以通过clone()方法或通过传递给定构造函数的对象来复制相同的内容来实现相同的操作。 复制构造函数用于创建具有相同现有对象值的对象的精确副本。
我们举一个例子来理解这一点 –
有一所大学有10,000名学生正在学习,大学必须有一个图书馆。
因此,该图书馆的数据库需要与所有学生完全相同的数据。
在这里,复制构造函数的作用发挥作用。
它将存储在每个学生对象中的数据从主数据库复制到库数据库,几乎没有错误。
如果我们现在没有使用复制构造函数,您可以想象它是多么笨拙和耗时的过程,它会带来更高的错误可能性。