为什么我们需要复制构造函数,什么时候应该在 java 中使用复制构造函数

Why do we need copy constructor and when should we use copy constructor in java

提问人:Avinash Reddy 提问时间:3/31/2015 最后编辑:soufrkAvinash Reddy 更新时间:9/27/2019 访问量:52750

问:

我正在浏览复制构造函数,我也浏览了堆栈流和其他链接。但我不清楚以下几点。

  1. 为什么我们需要一个复制构造函数
  2. 我们什么时候需要复制构造函数

我的意思是我们需要使用 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。Copy Constructor 将创建一个类似的对象,其值为 和 。但两者都是 2 个不同的对象,对 on 对象值的更改不会影响另一个对象。rollNo: 1name: avinashrollNo: 1name: avinash

这里的问题是

当我们有一个构造函数时,例如

public Employee(String rollNo, String name){
    this.rollNo = rollNo;
    this.name = name;
}

以创建对象。我们可以调用相同的构造函数来创建另一个对象。但是为什么我们需要调用复制构造函数呢?我们什么时候需要调用它?请解释

Java 复制构造函数

评论

1赞 Alex 3/31/2015
如果你没有看到创建这样的构造函数的意义,那么你就不需要它。
1赞 Makaveli84 11/22/2016
值得一提的是,上面示例中的复制构造函数尝试直接访问私有字段。它应该是 instead of 和 instead of .employee.getRollNo()employee.rollNoemployee.getName()employee.name
0赞 user207421 2/13/2018
1. 我们没有。2. 我在 Java 的 21 年里从未使用过。3. Java 中真的没有“复制构造函数”这样的东西。复制构造函数是 C++ 编译器在按值传递或返回对象或赋值对象时可以使用的东西。这些在 Java 中都不会发生。
0赞 Jim Balter 4/18/2022
@Makaveli84 从同一类中的方法访问私有字段没有错。
0赞 Makaveli84 4/18/2022
@JimBalter 这是合法的,但不是好的做法。AFAIK,通常建议调用 ters 和 ters,因为此类方法可能包含特定和/或额外的实现细节,而不是简单的字段分配。getset

答:

5赞 TheLostMind 3/31/2015 #1

如果您想拥有另一个与已有实例具有完全相同的值的实例,该怎么办?Employee

你会打电话吗?

setName(oldEmployee.getName())..
setRollNumber(oldEmployee.getRollNumber())..
etc..

与其这样做,不如使用它

Employee copyOfEmployeeOne=new Employee(employeeOneInstance);
// no need of a sequence of setters..

评论

0赞 Avinash Reddy 3/31/2015
我可以正确地调用常规构造函数。Employee copyOfEmployee = new Employee(1,avinash); .这还会创建与第一个对象具有相同值的 Employee 对象。
4赞 TheLostMind 3/31/2015
@AvinashReddy - 如果有 20 个属性?..怎么办如果您不知道 5 个属性的值,并且必须从另一个实例中获取它们,该怎么办?
38赞 Serge Ballesta 3/31/2015 #2

使用复制构造函数而不是传递所有参数的构造函数有 2 个很好的理由:

  1. 当您有一个具有许多属性的复杂对象时,使用 Copy 构造函数要简单得多
  2. 如果将属性添加到类中,则只需更改复制构造函数以考虑此新属性,而不是更改其他构造函数的每次匹配
2赞 zubergu 3/31/2015 #3

另一种情况是存储对象的“历史”值。

因此,您有一个对象,但每当您更改其状态时,您都希望将其添加到最适合您的任何数据结构中,而不是手动复制数据,您只需在进一步修改之前使用“复制构造函数”。ArrayList

34赞 skytreader 3/31/2015 #4

按照惯例,复制构造函数应提供对象的深层副本。正如其他答案中已经提到的,复制构造函数提供的主要便利是当你的对象变得过于复杂时。请注意,它提供了(几乎)类似的声明。java.lang.Cloneable

但是,在接口上使用复制构造函数有许多优点。Cloneable

  1. Cloneable因为接口实际上不提供任何方法。要使它有效,您仍然需要重写 .对于界面来说,这是一个非常违反直觉的用途。clonejava.lang.Object

  2. clone返回一个 .要使它有任何用处,您仍然需要进行类型转换。这很尴尬,可能会导致运行时错误。Object

  3. 该方法的记录很少。对于 ,如果最终字段指向可变对象,事情可能会搞砸。cloneclone

  4. 最重要的是,复制构造函数可以接受子类的深度复制实例。IMO,这是复制构造函数真正闪耀的地方。

还有更多的优点(参见 Joshua Bloch 的 Effective Java 2e),但这些是我发现与我目前所从事的工作最相关的几点。

[1] Java 语言中没有任何内容实际上提供了深度复制的默认结构。至多,对象只能告诉程序员,它们可以通过实现或提供复制构造函数来深度复制。Cloneable

4赞 Naresh Joshi 1/16/2017 #5

与 Object.clone() 方法相比,复制构造函数为我们提供了许多优势,因为它们

  1. 不要强迫我们实现任何接口或抛出异常。
  2. 不需要任何演员表。
  3. 不要要求我们依赖未知对象创建机制。
  4. 不要要求父类遵循任何约定或实现任何内容。
  5. 允许我们修改最终字段。
  6. 允许我们完全控制对象的创建,我们可以在其中编写我们的初始化逻辑。

阅读有关 Java Cloning - Copy Constructor versus Cloning 的更多信息

0赞 Srikant M 1/31/2018 #6

通过复制构造函数,我们可以在不使用许多复杂的东西(例如实现可克隆接口和覆盖克隆方法)的情况下进行克隆。此外,我们无需特别担心深度克隆。

但需要注意的几点是:

1.当我们实现Cloneable时,这是对其他类/用户的暗示,即该类的对象是可克隆的。否则,其他类可能没有关于可克隆的显式信息。

2.如果我们将复制构造函数设为私有,那么我们可以限制克隆这个类的对象。然后,此复制构造函数只能用于初始化本地类中新创建的对象,而不是用于其他类中的克隆目的。

3.当你不想让你的类可克隆,但如果你写了带有访问说明符的复制构造函数,那么它会导致其他类可以创建你的类对象的不安全感。

0赞 BinDev 3/15/2018 #7

复制构造函数实现了浅层和深度克隆机制,但与克隆相比,使用复制构造函数(使用可克隆接口)的主要优点是:

  1. 在使用 Object.clone() 方法时,我们不需要任何类型的大小写。
  2. 我们将能够修改最终字段以进行复制,这与在 Object.clone() 机制的情况下无法修改或访问最终字段不同。
  3. 它允许我们完全控制对象创建,我们可以在其中编写我们的初始化逻辑。
  4. 如果我们想克隆包含其他依赖类的引用变量的类的对象,我们不需要实现该类的克隆方法。只需初始化我们的复制构造函数,我们就可以实现这一点。
0赞 nabster 9/27/2019 #8

请考虑此示例,其中超类提供了一个复制构造函数,以隐式强制开发人员手动将字段复制到父类。这对于下投很有用:

public class Employee {
    private String name;
    private int age;

    // regular constructor
    public Employee(String name, int age) {
        this.name = name;
        this.age = age;
    }

    // copy constructor
    public Employee(Employee that) {
        this.name = that.name;
        this.age = that.age;
    }
    // getters & setters
}

public class SeniorMgmt extends Employee {
    private boolean secureAccess;

    public SeniorMgmt(Employee employee, boolean secureAccess) {
        super(employee);
        this.secureAccess = secureAccess;
    }
    // getters & setters
}

public class TestDrive {
    public static void main(String[] args) {
        Employee programmer = new Employee("John", 34);
        SeniorMgmt promotedProgrammer = new SeniorMgmt(programmer, true);
    }
}