繁体   English   中英

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

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

提示:本站收集StackOverFlow近2千万问答,支持中英文搜索,鼠标放在语句上弹窗显示对应的参考中文或英文, 本站还提供   中文繁体   英文版本   中英对照 版本,有任何建议请联系yoyou2525@163.com。

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

  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;
    }
}

复制构造函数用于创建对象的精确副本,该对象具有与现有对象相同的值。

例如,我们有一个值为rollNo: 1name: avinash的 Employee 。 Copy Constructor 将创建一个类似的对象,其值为rollNo: 1name: avinash 但两者都是 2 个不同的对象,对对象值的更改不会影响另一个对象。

这里的问题是

当我们有一个构造函数比如

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

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

8 个回复

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

  1. 当您有一个具有许多属性的复杂对象时,使用复制构造函数要简单得多
  2. 如果向类添加属性,只需更改复制构造函数以考虑此新属性,而不是更改其他构造函数的每次出现

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

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

  1. Cloneable作为接口实际上不提供任何方法。 为了使其有效,您仍然需要覆盖java.lang.Objectclone方法。 对于接口来说,这是一种非常违反直觉的用法。

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

  3. clone方法的记录很差。 对于clone ,如果您有指向可变对象的 final 字段,事情可能会变得一团糟。

  4. 最重要的是,复制构造函数可以接收子类的深度复制实例。 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..

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

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

阅读有关Java 克隆的更多信息- 复制构造函数与克隆

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

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

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

但需要注意的是:

1.当我们实现Cloneable时,是对其他类/用户的一个提示,该类的对象可以是可克隆的。 没有这个,其他类可能没有关于可克隆的明确信息。

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

3.当您不想使您的类可克隆时,如果您编写了带有访问说明符 public 的复制构造函数,则会导致其他类可以创建您类的对象的不安全性。

Copy Constructors 实现了浅层和深层克隆机制,但使用拷贝构造函数优于克隆(使用 Cloneable 接口)的主要优点是:

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

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

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);
    }
}
3 我什么时候应该在 C++ 构造函数参数中使用 const?

我对干净的代码/编码风格有疑问,疑问是,我什么时候应该在 C++ 构造函数参数中使用关键字const 。 例如,考虑以下类: 在这段代码中,我想初始化来自类A的引用b ,同时我想表示作为参数传递给类A构造函数的引用不会用于更改对象b_的值. 但是,显示的代码不会编译,编译器会显示以下消息: ...

4 什么时候不应该在构造函数中使用初始化列表?

当我们不应该在构造函数中使用初始化列表以及如何通过赋值来克服时,有人可以引用示例代码吗? 我正在寻找以下声明的一个例子 当您的类有两个构造函数需要以不同的顺序初始化this对象的数据成员时,可能会发生这种情况。 或者,当两个数据成员是自引用时,可能会发生这种情况。 或者当数据 ...

7 我什么时候应该在 C++ 中将复制\\移动构造函数标记为已删除? 应该考虑哪些方面?

我什么时候应该在 C++ 中将复制\\移动构造函数标记为已删除? 应该考虑哪些方面? 当复制\\移动构造函数既没有被删除也没有被用户定义的构造函数替换时,是否有任何我应该注意的潜在问题? 如果您能举几个简单的例子,包括 libc++ 或 libstdc++ 提供的例子,我将不胜感激。 我想了想,想 ...

2020-06-12 05:24:07 1 53   c++
8 什么时候应该在PHP中设置类属性-在构造函数中还是需要时?

我正在学习OOP PHP,并且努力了解何时设置变量。 我的课上有一堆变量,有些(但不是全部)函数使用了这些变量。 下面的代码显示了函数是否需要变量 1)检查当前是否设置 2)如果未设置,它将运行设置该变量的任何函数 是这样吗,还是应该使用__constructor函数设 ...

2018-01-16 21:25:18 2 41   php/ oop
9 什么时候应该在dart中使用final字段,工厂构造函数或带有getter的私有字段?

如果您知道如何重命名此问题,欢迎您提出建议。 在Dart语言中,可以编写带有final字段的类。 这些字段只能在构造函数主体运行之前设置。 在声明构造函数或使用this.field速记时,可以在初始化程序列表语法中进行声明(通常用于类内部的静态常量): 假设我实际上需要对实例创 ...

10 警告:应该在复制构造函数中明确初始化基类

我正在为CUDA处理编写一个矩阵类。 我编写了一个矢量类(以下称为Elements ),并将其用于矩阵基础。 这是模板定义: 应该注意的是,在Elements类和Matrix类中都没有动态分配任何内容。 我收到warning: base class 'struct El ...

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2022 STACKOOM.COM