java object 之clone方法全面解析

Java对象之clone方法全面解析

简介

在Java中,如果使用赋值号将一个对象赋值给另外一个对象,那么这两个对象会共用同一份数据。而通过clone()方法可以创建一个新的对象,并复制原始对象数据到新对象中。

在本篇文章中,我们将全面解析clone()方法,介绍如何使用clone()方法拷贝一个Java对象。

clone() 方法说明

clone()方法是Java中一个被重载的方法,它的主要作用是提供一种克隆方法,用于通过拷贝生成和原始对象完全相同数据的新对象。clone方法并不需要实现Cloneable接口,但是如果不实现的话,在调用clone方法时会抛出CloneNotSupportedException异常。

下面是clone方法的声明:

protected Object clone() throws CloneNotSupportedException

clone方法是一个受保护的方法,因此,只有该类和该类的子类才能访问该方法。如果想要在该类的外部访问该方法,需要在该类的内部定义一个public方法,并在该方法中调用clone方法。

clone的默认行为

通过clone方法,生成了新的对象,但这新的对象和原始对象的数据增加了一份引用。这意味着,如果新对象和原始对象中的某个数据被修改了,那么这两个对象中都会体现出来。

下面是一个例子:

class Person {
   String firstName;
   String lastName;
}

class MainClass {
   public static void main(String args[]) {
      Person originalPerson = new Person();
      originalPerson.firstName = "Tom";
      originalPerson.lastName = "Swift";

      Person newPerson = originalPerson.clone();
      newPerson.firstName = "John";

      System.out.println("Original Person First Name: " + originalPerson.firstName);
      System.out.println("New Person First Name: " + newPerson.firstName);
   }
}

在这个例子中,我们创建了一个Person对象,并将其赋值给一个引用变量(originalPerson)。然后,我们使用clone()方法创建了一个新的对象,并将其赋值给一个新的引用变量(newPerson)。我们将新对象的firstName属性设为John。我们在输出中查看每个对象的firstName属性值,发现原始对象的firstName属性值没有发生变化,而新的对象的firstName属性被修改了。

通过重写clone方法制定克隆的行为

因为clone方法的默认行为并不总是所期望的,所以你可能需要重写clone()方法来明确克隆的对象拷贝格式。在默认的情况下,clone()方法会生成一个新的对象,但是该对象中的数据项还是原来的数据项的引用(这是浅拷贝,shallow copy的一种)。在大多数情况下,这是无法满足需求的。

还是使用上面的Person类为例,在该类中增加一个address属性:

class Person {
   String firstName;
   String lastName;
   Address address;
}

class Address {
   String street;
   String city;
   String state;
}

现在尝试通过原始对象拷贝一个新的对象来进行数据的clone操作:

Person originalPerson = new Person();
originalPerson.firstName = "Tom";
originalPerson.lastName = "Swift";
originalPerson.address = new Address();
originalPerson.address.street = "31 Frost St.";
originalPerson.address.city = "New York";
originalPerson.address.state = "NY";

Person newPerson = originalPerson.clone();
newPerson.firstName = "John";
newPerson.address.street = "20 Broadway";

这段代码将会生成一个新的Person对象。因为Address对象中的属性都是引用拷贝,所以结果中,originalPerson对象和newPerson对象中的Address对象的street属性都会被修改,这显然背离了我们希望达到的效果。

在这种情况下,不使用clone方法是更好的选择。应该重写clone方法,将原始对象与新对象进行比较,并在必要时通过深拷贝变得不同。通过实现深拷贝,可以确保新对象中的每个属性都不是原始属性的引用。

下面是一个创建Person方法的示例,其中新对象中的Address属性被深拷贝:

class Person implements Cloneable {
   String firstName;
   String lastName;
   Address address;

   protected Object clone() throws CloneNotSupportedException {
      Person newPerson = (Person) super.clone();
      newPerson.address = (Address) newPerson.address.clone();
      return newPerson;
   }
}

class Address implements Cloneable {
    String street;
    String city;
    String state;

   protected Object clone() throws CloneNotSupportedException {
      return super.clone();
   }
}

如上所示,当我们在Person类和Address类中实现Cloneable接口时,就可以在深拷贝新对象时使用clone()方法。在这个示例中,当我们从原始对象进行深拷贝时,将新的Address对象相应地拷贝到新的Person对象中。

下面是一个演示深拷贝的例子:

Person originalPerson = new Person();
originalPerson.firstName = "Tom";
originalPerson.lastName = "Swift";
originalPerson.address = new Address();
originalPerson.address.street = "31 Frost St.";
originalPerson.address.city = "New York";
originalPerson.address.state = "NY";

Person newPerson = originalPerson.clone();
newPerson.firstName = "John";
newPerson.address.street = "20 Broadway";

System.out.println("Original Person Street: " + originalPerson.address.street);
System.out.println("New Person Street: " + newPerson.address.street);

在这个例子中,我们创建了一个Person对象,并将其赋值给一个引用变量originalPerson。我们还创建了一个新的Person对象,通过调用originalPerson对象的clone()方法来实现深拷贝,将其赋值给新创建的对象。我们修改了新对象的firstName属性,并将新对象的address属性地址设为20 Broadway。我们在输出中查看每个对象的address.street属性值,发现原始对象中的address.street属性值没有发生变化,而新对象的address.street属性被新复制了一份,值变为了20 Broadway,满足了我们的要求。

结论

clone()方法可以生成两个相同的Java对象,可以根据需要深度或浅拷贝对象。clone方法分为浅拷贝和深拷贝,浅拷贝复制的是引用地址,而深拷贝则是深层次的拷贝所有对象中的属性。

如果你决定在你的Java代码中使用clone()方法,你应该重写clone()方法,并遵循在上面提到的建议。

阅读剩余 68%

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:java object 之clone方法全面解析 - Python技术站

(0)
上一篇 2023年5月26日
下一篇 2023年5月26日

相关文章

  • javascript实现动态统计图开发实例

    下面我将为您详细讲解“JavaScript实现动态统计图开发实例”的完整攻略。 1. 准备工作 在实现动态统计图之前,需要准备以下工具和资源: 数据可视化库:例如ECharts、D3.js、Highcharts等; 前端框架:例如Vue.js、React.js等; 数据源:可以是本地数据,也可以是网络接口返回的数据。 2. 选择可视化库 在选择可视化库时,需…

    Java 2023年6月16日
    00
  • Java编程中的性能优化如何实现

    下面是Java编程中的性能优化攻略,共分为四个步骤: 1. 定位瓶颈 性能优化的第一步是定位瓶颈,只有知道哪里出了问题才能有针对性地进行优化。我们可以使用一些工具来定位瓶颈,比如: JProfiler:一款功能强大的Java性能分析工具,在视图中可以观察到CPU使用率、内存占用、线程状态、对象创建等性能特征,帮助我们快速定位瓶颈。 Java Mission …

    Java 2023年5月24日
    00
  • SpringBoot封装响应处理超详细讲解

    在Spring Boot中,我们可以通过封装响应处理来统一处理返回结果,使得代码更加简洁、易读、易维护。以下是Spring Boot封装响应处理的详细攻略: 1. 封装响应处理的基本思路 封装响应处理的基本思路是:定义一个通用的响应对象,包含响应状态码、响应消息、响应数据等信息。在控制器中,将业务处理的结果封装到响应对象中,然后返回响应对象。在响应处理器中,…

    Java 2023年5月14日
    00
  • Java异常处理机制try catch流程详解

    Java异常处理机制try catch流程详解 1. 异常处理机制概述 在Java程序中,当出现异常时,会有异常信息抛出,如果不加以处理,程序可能会出现崩溃等异常情况。因此我们需要加入异常处理机制来避免这些问题的出现。 Java异常处理机制是一种解决异常情况的方式,Java提供了try-catch-finally语句用于异常处理。 2. try-catch-…

    Java 2023年5月27日
    00
  • Mybatis自关联查询一对多查询的实现示例

    下面是详细讲解“Mybatis自关联查询一对多查询的实现示例”的完整攻略。 什么是自关联查询 自关联查询是指在一个表中通过外键的方式连接同一张表的两行或多行数据的查询方式。比如,在员工表中,如果需要查询员工和他们的直接上级,可以通过员工表中的经理编号字段来连接同一员工表。 自关联查询的实现 自关联查询在Mybatis框架下的实现方式有两种: 使用Mybati…

    Java 2023年5月20日
    00
  • spring boot 配置动态刷新详解

    SpringBoot配置动态刷新详解 在SpringBoot应用程序中,我们通常需要对配置进行修改,但是修改后需要重启应用程序才能生效,这对于生产环境来说是不可接受的。为了解决这个问题,SpringBoot提供了配置动态刷新功能,可以在不重启应用程序的情况下更新配置。本文将详细介绍SpringBoot配置动态刷新的实现原理和使用方法。 实现原理 Spring…

    Java 2023年5月15日
    00
  • Spring Data JPA 注解Entity关联关系使用详解

    Spring Data JPA是在JPA规范基础上进行了扩展的一种Persistence Framework。在Spring Data JPA中,我们需要使用注解来描述实体类之间的关系。下面,我们将详细讲解“Spring Data JPA 注解Entity关联关系使用详解”的完整攻略。 一、@OneToOne 注解 @OneToOne注解表示一对一关系,常见…

    Java 2023年5月20日
    00
  • springboot集成schedule实现定时任务

    下面是springboot集成schedule实现定时任务的完整攻略: 1. 学习前提 在学习本篇攻略之前,需要掌握以下基础知识: Java基础语法 Spring框架基础知识 SpringBoot框架基础知识 2. Schedule简介 Schedule是Spring框架提供的一种任务调度框架,用于在指定的时间间隔内执行指定的任务。Schedule有以下几种…

    Java 2023年5月15日
    00
合作推广
合作推广
分享本页
返回顶部