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 数组ArrayList常用语法详解

    Java 数组ArrayList常用语法详解 1. 简介 Java数组ArrayList是Java中常用的一种数据结构,可以存储大量元素。相比于普通数组,Java数组ArrayList拥有更多的便捷的方法和更灵活的容量管理。本篇攻略将详细讲解Java数组ArrayList的常用语法和示例。 2. 定义和初始化 2.1 定义 Java数组ArrayList定义…

    Java 2023年5月26日
    00
  • Java如何执行cmd命令

    Java可以通过Runtime类或ProcessBuilder类来执行cmd命令。 使用Runtime类执行cmd命令 Runtime类提供了用于与运行时环境进行交互的方法。通过它的exec方法可以执行给定的字符串命令,并返回表示进程的Process对象。 以下为示例代码: import java.io.*; public class CmdDemo { p…

    Java 2023年5月26日
    00
  • 微信开发准备第二步 springmvc mybatis项目结构搭建

    微信开发准备第二步 springmvc mybatis项目结构搭建是微信公众号开发的重要步骤之一。下面是该步骤的完整攻略: 步骤一:创建Maven项目 我们可以使用Maven来创建一个新的SpringMVC MyBatis项目。在创建项目时,我们需要选择“webapp”类型的项目,并添加SpringMVC和MyBatis的依赖。下面是一个示例的pom.xml…

    Java 2023年5月17日
    00
  • Java的Swing编程中使用SwingWorker线程模式及顶层容器

    Java的Swing编程中,使用SwingWorker线程模式以及顶层容器可以实现多线程的UI操作,避免了长时间运行的任务卡住了界面的情况。下面将详细介绍如何使用SwingWorker线程模式及顶层容器进行Swing编程。 一、SwingWorker线程模式 SwingWorker是Java提供的一个工具类,用于在后台线程中执行耗时的任务,并在任务完成后通知…

    Java 2023年5月26日
    00
  • Java从控制台读入数据的几种方法总结

    下面是“Java从控制台读入数据的几种方法总结”的完整攻略。 一、从控制台读入数据的几种方法 在Java中,可以通过以下几种方式从控制台读入数据: 使用Scanner类读入用户输入数据。 使用BufferedReader类读入用户输入数据。 使用System.in.read()方法读入用户输入的字符。 下面我们将分别详细说明这三种方法的具体使用。 1. 使用…

    Java 2023年5月26日
    00
  • 一文搞懂MyBatis多数据源Starter实现

    一文搞懂MyBatis多数据源Starter实现 多数据源在一些应用场景下非常常见,MyBatis也提供了多数据源的支持。但是对于开发者来说,要手动实现多数据源的切换非常繁琐,而且容易出错。MyBatis多数据源Starter可以帮助我们自动配置多数据源并提供切换功能。本文将对MyBatis多数据源Starter的使用进行详细讲解。 步骤一:添加依赖 首先,…

    Java 2023年5月20日
    00
  • SSH框架网上商城项目第3战之使用EasyUI搭建后台页面框架

    下面是 “SSH框架网上商城项目第3战之使用EasyUI搭建后台页面框架” 的完整攻略。 概述 本文将详细介绍如何使用EasyUI搭建后台管理系统页面框架。具体来说,我们将通过以下步骤实现: 引入EasyUI框架和jQuery库; 编写HTML代码,建立基础的页面框架结构; 编写JavaScript代码,调用EasyUI组件,实现各种页面布局、交互效果和表单…

    Java 2023年5月20日
    00
  • Java编程接口调用的作用及代码分享

    下面我将详细讲解“Java编程接口调用的作用及代码分享”的完整攻略。 Java编程接口调用的作用 Java编程接口(API)是Java标准库中的一组类和接口,用于提供基本的程序操作功能。Java API包含了很多常用的类,比如String、Math和ArrayList等,可以帮助程序员快速进行开发。 Java编程接口调用的作用是在程序中调用Java API提…

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