Java 克隆示例2025年3月17日 | 阅读 12 分钟 对象克隆(Object cloning)是指创建对象的精确副本。它会创建一个与当前对象同类的类的新实例,并用当前对象中的对应字段中的所有对象来初始化它。 使用赋值运算符创建引用变量的副本, 在 Java 中,没有运算符可以创建对象的副本。与 C++ 不同,在 Java 中,如果我们使用赋值运算符,它将创建引用变量的副本而不是对象的副本。可以通过一个示例来解释这一点。以下示例显示了相同的内容。 示例输出 ![]() 使用 clone() 方法创建副本要复制其对象的类必须在其本身或其某个父类中定义一个公共的 clone 方法。 每个实现 clone() 的类都应调用 super.clone() 以获取克隆的对象引用。 要复制的对象所在的类还必须实现 Java.lang.Cloneable 接口。否则,当访问该类对象的克隆方法时,将抛出 CloneNotSupportedException。 语法 protected Object clone() throws CloneNotSupportedException 对象克隆的类型
当我们使用 clone 方法的默认实现时,我们会得到对象的浅拷贝,这意味着它会创建一个新实例,并将对象的所有字段复制到该新实例中,然后将其作为对象类型返回。我们需要将其显式地转换回我们的原始对象。这是对象的浅副本。 Object 类的 clone() 方法支持对象的浅副本。如果对象在浅副本中包含原始类型和非原始类型或引用类型变量,则克隆的对象也引用与原始对象引用的相同对象,因为只有对象引用被复制,而不是被引用的对象本身。 这就是为什么在 Java 中称为浅拷贝或浅克隆。如果只有原始类型字段或不可变对象存在,那么在 Java 的浅副本和深副本之间就没有区别。 clone() 方法示例 - 浅拷贝在下面的代码示例中,clone() 方法创建了一个具有不同 hashCode 值的新对象,这意味着它在不同的内存区域。但是,由于 Test 对象 c 位于 Test2 中,因此原始类型已实现深拷贝,但此 Test 对象 c 仍在 t1 和 t2 之间共享。为了解决这个问题,我们显式地为对象变量 c 创建了深拷贝。 创建浅拷贝的示例程序 输出 ![]() 在上面的示例中,t1.clone 返回对象 t1 的浅副本。要获得对象的深拷贝,在获得副本后,需要在 clone 方法中进行一些更改。 clone() 方法示例 - 深拷贝如果我们想创建一个对象 X 的深拷贝并将其放入另一个对象 Y 中,那么将创建对任何被引用对象字段的新副本,并将这些引用放入对象 Y 中。这意味着在对象 X 或 Y 的被引用对象字段中所做的任何更改都将仅反映在该对象中,而不会反映在另一个对象中。在下面的示例中,我们创建了对象的深拷贝。 深拷贝会复制所有字段并创建被引用的动态分配内存的副本。当复制一个对象以及它引用的对象时,就会发生深拷贝。 创建深拷贝的示例程序 输出 ![]() 在上面的示例中,我们可以看到已经为 HelloWorld 类分配了一个新对象来复制将返回给 clone 方法的对象。因此,t2 将获得对象 t1 的深拷贝。所以 t2 对 'c' 对象字段所做的任何更改都不会反映在 t1 中。 浅拷贝和深拷贝的区别
深拷贝和浅拷贝相同的场景1. 在 Strings 中 我们需要了解复制字符串时会发生什么。我们都知道字符串被视为 Java.lang 包中 String 类的对象。因此,与其他对象一样,当我们进行复制时,会复制引用。 示例 输出 ![]() 解释 程序的输出显示引用变量 s1 和 s2 显示的哈希码相同。这意味着引用变量 obj1 和 obj2 指向相同的内存地址。但是,问题是,我们可以说我们在上面的程序中进行了浅拷贝吗,因为引用是相同的?答案是否定的。以下示例为我们提供了足够的证据来验证给出的答案。 示例 输出 ![]() 解释 程序的输出告诉我们,引用变量 s1 显示的哈希码与引用变量 s2 显示的哈希码不相等。此外,使用引用变量 s2 所做的更改不会由引用变量 s1 显示。这是因为 Java 中的字符串始终是不可变的。因此,当 s2 更改 s1 的内容时,它最终会创建一个全新的字符串。因此,先前的字符串保持不变,引用变量 obj2 指向新的字符串对象所在的新内存位置。 我们已经看到,字符串的更改会导致创建新的字符串对象。因此,复制字符串不能称为深拷贝,也不能称为浅拷贝。事实上,当我们在 Java 中处理字符串时,深拷贝和浅拷贝之间没有区别。 2. 在原始数据类型中我们需要了解复制原始数据类型时会发生什么。与字符串不同,原始数据类型不是对象。但是,与字符串一样,在原始数据类型中没有深拷贝或浅拷贝的概念。请注意下面的示例。 输出 ![]() 解释 当 s2 的值被更新时,它不会影响 s1 的值。这是因为 y 已经有了自己的内存分配。它不指向 s1 的内存地址。因此,赋值 s2 = s1;只是将 s1 的值复制到 s2。因此,y 中的任何更新都不会影响 x。类似的约定也适用于其他原始数据类型。在这里,s2 的内存分配也是自动发生的。 在 Java 中,没有标准的规定何时使用浅拷贝以及何时使用深拷贝。这取决于程序员或设计师决定他们想要使用什么。因此,建议先理解需求,然后再明智地选择深拷贝和浅拷贝。 clone() 方法的优点
clone() 方法的缺点
下一个主题Java 中的支付网关集成 |
Java 序列化是 Java 的一项功能,它允许将对象转换为字节流,反之亦然,这对于数据持久化或网络通信非常有用。但是,使用 Java 序列化存在一些缺点,例如它缺乏跨平台...
阅读 8 分钟
在 Java 中,变量是保存值的容器。变量名表示内存位置的名称。每个变量包含三个元素:数据类型、变量名和值。变量可能具有作用域(私有、受保护),但这取决于需求。数据类型:它定义...
阅读 4 分钟
getChannel() 方法定义在 Java.io.FileInputStream 类中。getChannel() 方法是创建文件的 FileChannel 实例的入口点。它通常在 FileInputStream、FileOutputStream 和 RandomAccessFile 等类中可用。FileInputStream 我们可以使用 FileInputStream 从文件中读取数据。如果我们想...
5 分钟阅读
反转字符串是编程中常见的项目,可以通过各种策略来实现。其中一种技术是使用 Java 中的 for 循环。在本文中,我们将了解如何...
阅读 4 分钟
? Java 程序经常需要解析日期和时间,尤其是那些涉及计划、事件管理和数据分析的程序。LocalDate、LocalTime、LocalDateTime 和 DateTimeFormatter 类只是 Java 中用于处理日期和时间的类和方法中的一部分。要分解日期和...
阅读 4 分钟
在 Java 中,ConcurrentModificationException 是一个异常,它告诉我们当其元素正在被并发遍历时,集合在结构上发生了修改。这通常发生在迭代器正在迭代集合时(例如,添加或删除元素)。让...
14 分钟阅读
Java 是一种灵活的编程语言,提供多种数据结构来组织数据集。Map(如 HashMap 和 TreeMap)在需要将键映射到值的情况下非常重要。然而,在某些情况下,您必须将一个键链接到更多...
阅读 4 分钟
Java LinkedHashMap 与 HashMap LinkedHashMap 与 HashMap 非常相似,并增加了维护插入元素顺序的功能。HashMap 提供了插入、删除和搜索元素的简便方法,但它不提供维护和跟踪……
阅读 10 分钟
最大子数组问题构成了算法问题中的一个高效算法,可以使用 Kadane 算法解决。这里的问题是找到连续子数组的最大和,可以在一维数组中以 O(n) 的时间复杂度解决。此……
阅读 4 分钟
在编程世界中,有很多时候您需要处理图像并将其作为字节处理。无论您是在处理文件上传、网络协议还是任何其他需要传输或操作图像数据的场景,了解如何...
5 分钟阅读
我们请求您订阅我们的新闻通讯以获取最新更新。
我们提供所有技术(如 Java 教程、Android、Java 框架)的教程和面试问题
G-13, 2nd Floor, Sec-3, Noida, UP, 201301, India