java 中clone()的使用方法

Java 中 clone() 的使用方法

什么是 clone() 方法

clone() 方法是一个 Object 类下的方法,用于返回对象的一个副本。如果一个类要使用 clone() 方法,则这个类必须实现 Cloneable 接口并覆盖 clone() 方法,否则会抛出 CloneNotSupportedException 异常。

如何使用 clone() 方法

实现 Cloneable 接口

实现 Cloneable 接口的类是为了表明这个类是可以进行拷贝的。Cloneable 接口没有方法需要实现,只是强调一个类能否被克隆。如下是一个橘子(Orange)类的示例:

public class Orange implements Cloneable {
    private String name;
    private Double weight;

    public Orange(String name, Double weight) {
        this.name = name;
        this.weight = weight;
    }

    public String getName() {
        return name;
    }

    public Double getWeight() {
        return weight;
    }

    @Override
    public Orange clone() throws CloneNotSupportedException {
        return (Orange) super.clone();
    }
}

如上例中,我们实现了 Cloneable 接口,并重写了 clone() 方法,没有特别的逻辑,直接调用了超类的 clone() 方法。

注意:如果要实现深拷贝,需要在重写的 clone() 方法中进行特定的逻辑实现。

使用 clone() 方法

我们可以通过如下方式来调用 clone() 方法:

Orange orange1 = new Orange("桔子", 0.3);
try {
    Orange orange2 = orange1.clone();
    System.out.println("orange1: " + orange1);
    System.out.println("orange2: " + orange2);
} catch (CloneNotSupportedException e) {
    e.printStackTrace();
}

运行结果如下:

orange1: com.example.Orange@15db9742
orange2: com.example.Orange@6d06d69c

可以看到返回的两个对象的 hashcode 不同,说明这两个对象实际上是两份不同的副本。经过 clone() 之后,orange1 和 orange2 两个橘子类的实例相同,但内存地址不同,互相独立,修改 orange1 的属性不会影响 orange2。

其他注意事项

由于 Object 类的 clone() 方法访问限制比较高,我们在使用时,有另外的三种可以使用的 clone 方法,分别是:

  • 浅拷贝;
  • 深拷贝;
  • 序列化拷贝。

在具体开发中,可以根据实际需要选择不同的拷贝方式。

示例说明

浅拷贝示例

浅拷贝的对象引用属性不进行克隆,新建对象中的属性引用与原始对象中的属性引用是相同的。如:

public class Apple implements Cloneable {
    private String name;
    private Double weight;
    private Date date;

    public Apple(String name, Double weight, Date date) {
        this.name = name;
        this.weight = weight;
        this.date = date;
    }

    public String getName() {
        return name;
    }

    public Double getWeight() {
        return weight;
    }

    public Date getDate() {
        return date;
    }

    @Override
    public Apple clone() throws CloneNotSupportedException {
        return (Apple) super.clone();
    }
}

public class Cook {
    public static void main(String[] args) {
        try {
            Apple apple1 = new Apple("红苹果", 0.5, new Date());
            Apple apple2 = apple1.clone();

            System.out.println("apple1: " + apple1);
            System.out.println("apple2: " + apple2);
            System.out.println("是否是同一对象: " + (apple1 == apple2));
            System.out.println("apple1.name: " + apple1.getName());
            System.out.println("apple2.name: " + apple2.getName());
            System.out.println("是否是同一对象: " + (apple1.getName() == apple2.getName()));
            System.out.println("apple1.date: " + apple1.getDate());
            System.out.println("apple2.date: " + apple2.getDate());
            System.out.println("是否是同一对象: " + (apple1.getDate() == apple2.getDate()));
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }
    }
}

运行结果如下:

apple1: com.example.Apple@15db9742
apple2: com.example.Apple@6d06d69c
是否是同一对象: false
apple1.name: 红苹果
apple2.name: 红苹果
是否是同一对象: true
apple1.date: Thu Nov 19 14:22:14 CST 2020
apple2.date: Thu Nov 19 14:22:14 CST 2020
是否是同一对象: true

深拷贝示例

深拷贝是指完全克隆一个对象,即属性引用与原始对象中的属性引用不是相同的,而是新建的。如:

public class Banana implements Cloneable {
    private String name;
    private Double weight;
    private Orange orange;

    public Banana(String name, Double weight, Orange orange) {
        this.name = name;
        this.weight = weight;
        this.orange = orange;
    }

    public String getName() {
        return name;
    }

    public Double getWeight() {
        return weight;
    }

    public Orange getOrange() {
        return orange;
    }

    @Override
    public Banana clone() throws CloneNotSupportedException {
        Banana banana = (Banana) super.clone();
        banana.orange = orange.clone();
        return banana;
    }
}

public class Cook {
    public static void main(String[] args) {
        try {
            Orange orange = new Orange("桔子", 0.3);
            Banana banana1 = new Banana("香蕉", 0.2, orange);
            Banana banana2 = banana1.clone();

            System.out.println("banana1: " + banana1);
            System.out.println("banana2: " + banana2);
            System.out.println("是否是同一对象: " + (banana1 == banana2));
            System.out.println("banana1.orange: " + banana1.getOrange());
            System.out.println("banana2.orange: " + banana2.getOrange());
            System.out.println("是否是同一对象: " + (banana1.getOrange() == banana2.getOrange()));
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }
    }
}

运行结果如下:

banana1: com.example.Banana@15db9742
banana2: com.example.Banana@6d06d69c
是否是同一对象: false
banana1.orange: com.example.Orange@7852e922
banana2.orange: com.example.Orange@4e515669
是否是同一对象: false

序列化拷贝示例

使用序列化拷贝可以将对象进行二进制序列化,然后再将序列化后的二进制数据反序列化为一个新的对象。如:

public class Watermelon implements Serializable {
    private String name;
    private Double weight;

    public Watermelon(String name, Double weight) {
        this.name = name;
        this.weight = weight;
    }

    public String getName() {
        return name;
    }

    public Double getWeight() {
        return weight;
    }
}

public class Cook {
    public static void main(String[] args) {
        Watermelon watermelon1 = new Watermelon("西瓜", 5.0);
        try {
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            ObjectOutputStream oos = new ObjectOutputStream(baos);
            oos.writeObject(watermelon1);

            ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
            ObjectInputStream ois = new ObjectInputStream(bais);
            Watermelon watermelon2 = (Watermelon) ois.readObject();

            System.out.println("watermelon1: " + watermelon1);
            System.out.println("watermelon2: " + watermelon2);
            System.out.println("是否是同一对象: " + (watermelon1 == watermelon2));
        } catch (IOException | ClassNotFoundException e) {
            e.printStackTrace();
        }
    }
}

运行结果如下:

watermelon1: com.example.Watermelon@15db9742
watermelon2: com.example.Watermelon@6d06d69c
是否是同一对象: false

总结

以上就是Java中clone()的使用方法,可以实现对象的拷贝功能。当然,使用时也要注意一些细节问题,根据实际场景选择对应的拷贝方式。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:java 中clone()的使用方法 - Python技术站

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

相关文章

  • 关于kafka发送消息的三种方式总结

    关于kafka发送消息的三种方式总结,是一篇介绍kafka发送消息的方法的文章,有助于理解kafka在分布式系统中的作用。这篇文章结合了官方文档和各种实践经验,详细介绍了kafka发送消息的三种方式,并提供了示例代码。 1. 普通的同步发送 kafka的producer提供了send()方法,可以通过这个方法来发送消息。在发送消息时,可以指定消息所属的top…

    Java 2023年5月20日
    00
  • 排查Java应用内存泄漏问题的步骤

    当Java应用使用内存过多、频繁抛出OutOfMemoryError异常时,可能会存在内存泄漏问题。以下是排查Java应用内存泄漏问题的一般步骤,供参考: 第一步,确认是否存在内存泄漏 内存泄漏是指内存占用数不断增长,直到应用崩溃。Java应用的内存占用通常分为两部分,一部分是堆内存,另一部分是非堆内存。可以通过以下方法确认是否存在内存泄漏问题: 使用jco…

    Java 2023年5月27日
    00
  • ES6知识点整理之模块化的应用详解

    关于“ES6知识点整理之模块化的应用详解”的完整攻略,以下是我的分享: 1. 概述 在ES6中,我们可以使用模块化来组织和管理代码,这也是ES6语法中比较重要的一个知识点。通过模块化,我们可以把一个大文件拆分成多个小文件,每个小文件只负责一个特定的功能,这样既方便代码的维护,也提高了代码的可读性和可复用性。 2. 模块化的基础语法 在ES6中,可以使用imp…

    Java 2023年5月26日
    00
  • 什么是死锁?

    以下是关于死锁的完整使用攻略: 什么是死锁? 死锁是指两个或多个线程在执行过程中,因互相等待对方释放资源而陷入的一种僵局。在死锁状态下,每个线程都在等待其他线程释放资源,从而导致线程都无法继续执行下去。锁是多线程编程中的一种常见问题,如果不加以处理,可能会导致程序崩溃。 死锁的原因 死锁的原因主要有两个方面: 竞争资源:当多个线程竞争同资源时可能会导致死锁。…

    Java 2023年5月12日
    00
  • Java 字符串转float运算 float转字符串的方法

    一、Java字符串转float运算 在Java中,可以通过以下的方式将字符串转换为float类型: 1.使用Float.parseFloat(String str)方法进行转换: String s1 = "5.5"; float f1 = Float.parseFloat(s1); System.out.println("f1 …

    Java 2023年5月27日
    00
  • 解决JSONObject.toJSONString()输出null的问题

    当我们调用 JSONObject.toJSONString(obj) 方法时,如果 obj 对象中存在 null 值的属性,那么转换成 JSON 字符串时就会出现问题,最终输出 null 值或抛出异常。下面我们来详细讲解如何解决此问题,以下是完整攻略: 1. 基本原因 在 JSONObject.toJSONString() 方法中,会检查对象 obj 是否为…

    Java 2023年5月26日
    00
  • java8中:: 用法示例(JDK8双冒号用法)

    当我们在Java8中使用Lambda表达式(Functional Interface)时,我们通常使用双冒号(::)操作符来引用方法。这种方式也称为方法引用(Method Reference),它提高了程序的可读性和简化了代码。 与Lambda表达式类似,方法引用也需要和特定的Functional Interface搭配使用。在Java 8中,Java中提供…

    Java 2023年5月26日
    00
  • SpringBoot参数校验之@Validated的使用详解

    下面就为大家详细讲解“SpringBoot参数校验之@Validated的使用详解”。 什么是@Validated 在Spring框架中,我们经常需要对方法入参的校验,以保证参数的正确性。 SpringBoot基于Hibernate Validator,为开发者提供了方便简洁的实现方式:@Validated。 @Validated 用于校验方法入参,可以将该…

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