Java中的clone方法实例详解

Java中的clone方法实例详解

什么是clone方法

clone()方法是Object类提供的一个protected方法,实现对象的复制(克隆)。通过调用对象的clone()方法返回一个复制后的对象,对象的类型与原对象的类型相同。

clone方法的实现

  • Object中的clone方法是原生方法,性能非常高。因此,我们在实现clone方法时要重写clone方法,并调用super.clone()方法实现克隆。

  • 如果需要深层次的复制,则需要重写clone方法,并且对需要克隆的属性进行深度克隆。

代码示例

浅拷贝示例

下面是一个浅拷贝示例

public class Person implements Cloneable{
    private String name;
    private int age;
    private Address address;

    public Person(String name, int age, Address address) {
        this.name = name;
        this.age = age;
        this.address = address;
    }

    @Override
    public Object clone() {
        try {
            return super.clone();
        } catch (CloneNotSupportedException e) {
            throw new RuntimeException(e);
        }
    }

    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", address=" + address +
                '}';
    }

    public static void main(String[] args) {
        Address a = new Address();
        a.setAddress("China");

        Person p1 = new Person("张三", 20, a);
        Person p2 = (Person) p1.clone();

        System.out.println(p1);
        System.out.println(p2);

        a.setAddress("USA");

        System.out.println(p1);
        System.out.println(p2);
    }
}

class Address {
    private String address;

    public String getAddress() {
        return address;
    }

    public void setAddress(String address) {
        this.address = address;
    }

    @Override
    public String toString() {
        return "Address{" +
                "address='" + address + '\'' +
                '}';
    }
}

在上述示例中,我们创建了一个Person类,其中包含了一个address属性,类型为自定义Address类对象。Person类实现了Cloneable接口,并重写了clone方法。在main函数中,我们创建了一个Person对象p1,并将其浅拷贝给p2。然后,我们修改了address属性的值,并打印出了p1和p2的地址信息。运行结果如下所示:

Person{name='张三', age=20, address=Address{address='China'}}
Person{name='张三', age=20, address=Address{address='China'}}
Person{name='张三', age=20, address=Address{address='USA'}}
Person{name='张三', age=20, address=Address{address='USA'}}

从结果中可以看到,虽然我们修改了a的值(在地址信息中,将China改为USA),但是p2还是指向了原先的地址。这是因为在浅拷贝中,只有基本数据类型和String类型的属性会进行值传递,而非基本数据类型和String类型的属性会被当作引用传递。在浅拷贝中,复制后的对象与被复制对象共用一份成员变量,因此,当成员变量值发生改变时,会影响另一个对象。

深拷贝示例

下面是一个深拷贝示例:

public class Person implements Cloneable{
    private String name;
    private int age;
    private Address address;

    public Person(String name, int age, Address address) {
        this.name = name;
        this.age = age;
        this.address = address;
    }

    @Override
    public Object clone() {
        try {
            Person person = (Person) super.clone();
            person.address = (Address) address.clone();
            return person;
        } catch (CloneNotSupportedException e) {
            throw new RuntimeException(e);
        }
    }

    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", address=" + address +
                '}';
    }

    public static void main(String[] args) {
        Address a = new Address();
        a.setAddress("China");

        Person p1 = new Person("张三", 20, a);
        Person p2 = (Person) p1.clone();

        System.out.println(p1);
        System.out.println(p2);

        a.setAddress("USA");

        System.out.println(p1);
        System.out.println(p2);
    }
}

class Address implements Cloneable{
    private String address;

    public String getAddress() {
        return address;
    }

    public void setAddress(String address) {
        this.address = address;
    }

    @Override
    public Object clone() {
        try {
            return super.clone();
        } catch (CloneNotSupportedException e) {
            throw new RuntimeException(e);
        }
    }

    @Override
    public String toString() {
        return "Address{" +
                "address='" + address + '\'' +
                '}';
    }
}

在上述示例中,我们在Person类中对需要深度拷贝的引用类型属性进行了深度拷贝。其中,Address类也实现了Cloneable接口,并重写了clone方法。在Main函数中,我们又创建了一个Address类型的对象a,并将其传入Person类的构造函数。通过打印a的信息可以看出,a地址为China。然后,我们将p1浅拷贝给p2,打印出p1和p2的信息,再次通过改变a的地址为USA打印出p1和p2的信息。运行结果如下所示:

Person{name='张三', age=20, address=Address{address='China'}}
Person{name='张三', age=20, address=Address{address='China'}}
Person{name='张三', age=20, address=Address{address='China'}}
Person{name='张三', age=20, address=Address{address='USA'}}

从结果中可以看到,我们通过修改a的地址为USA后,p1和p2的address属性的地址都发生了改变,因为他们两个都拥有一个自己的Address对象。因此,在进行深拷贝时,需要对被拷贝对象的引用类型属性进行深度拷贝。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:Java中的clone方法实例详解 - Python技术站

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

相关文章

  • Java异常(Exception)处理以及常见异常总结

    关于Java异常处理以及常见异常总结的攻略共分为以下几个部分: 异常概念 Java异常分类 异常处理 常见异常总结 示例说明 1. 异常概念 Java异常是在程序执行期间出现的错误或异常情况。异常在程序执行过程中会中断程序的正常执行,并且在出现问题的位置抛出异常信息。一个方法如果没有特殊处理异常的机制,当出现异常时会使程序崩溃。 2. Java异常分类 Ja…

    Java 2023年5月26日
    00
  • 详解Java基础知识——JDBC

    详解Java基础知识——JDBC JDBC的介绍 JDBC(Java Database Connectivity)是Java语言中用于操作关系型数据库的API,通过JDBC可以实现Java与数据库之间的交互。JDBC主要包含以下几个部分: DriverManager:驱动管理器,用于管理各种数据库驱动。 Connection:连接对象,用于与数据库建立连接。…

    Java 2023年5月19日
    00
  • C++异常处理 try,catch,throw,finally的用法

    C++异常处理 try,catch,throw,finally的用法 在C++中,异常处理机制是一种用于处理程序运行时出现错误的机制。当程序发生错误时,通常会中断其继续执行。异常处理机制能够使程序有机会处理这些错误,并继续执行而不崩溃。 try-catch块 在C++中,异常处理块包括try-catch块和finally块。try-catch块是一个用来捕捉…

    Java 2023年5月26日
    00
  • ajax动态赋值echarts的实例(饼图和柱形图)

    我将详细讲解“ajax动态赋值echarts的实例(饼图和柱形图)”的完整攻略。以下是具体步骤: 准备工作 在HTML文件中引入ECharts的JS文件和相应的主题文件 <!– 引入ECharts插件的JS库 –> <script src="https://cdn.bootcdn.net/ajax/libs/echarts/4…

    Java 2023年6月15日
    00
  • java的Hibernate框架报错“HibernateException”的原因和解决方法

    原因 “HibernateException” 错误通常是以下原因引起的: Hibernate 配置问题:如果您的 Hibernate 配置存在问题,则可能会出现此错误。在这种情况下,需要检查您的 Hibernate 配置并确保它们正确。 数据库连接问题:如果您的数据库连接存在问题,则可能会出现此错误。在这种情况下,需要检查您的数据库连接并确保它们正确。 H…

    Java 2023年5月4日
    00
  • Java实现导出Excel功能

    下面我将详细讲解Java实现导出Excel功能的完整攻略,过程中包含以下几个步骤: 导入POI依赖 创建Excel工作簿和工作表 设置表头 向表中填充数据 导出Excel文件 1. 导入POI依赖 POI是Java操作Excel的开源项目,我们需要在项目中导入POI的相关依赖,这里以Maven为例,添加以下依赖即可: <dependency> &…

    Java 2023年5月26日
    00
  • Sprint Boot @Controller使用方法详解

    @Controller是Spring Boot中的一个注解,它用于标记一个类为控制器类。在使用Spring Boot开发Web应用程序时,@Controller是非常有用的。本文将详细介绍@Controller的作用和使用方法,并提供两个示例说明。 @Controller的作用 @Controller的作用是标记一个类为控制器类。控制器类是指处理HTTP请求…

    Java 2023年5月5日
    00
  • JDBC+GUI实现简单学生管理系统

    好的。首先,我们需要明确几个概念: JDBC:Java Database Connectivity,Java数据库连接技术,用于在Java程序中访问和操作数据库的API。 GUI:Graphical User Interface,图形用户界面,用于设计和实现用户交互的界面。 学生管理系统:用于管理学生信息的软件,包括学生的基本信息、成绩等。 接下来,我们详细…

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