Java 中的浅拷贝与深拷贝

2025年9月4日 | 阅读7分钟

在本节中,我们将讨论 Java 中浅拷贝和深拷贝之间的主要区别。让我们来理解浅拷贝和深拷贝。

浅拷贝

当我们复制某个实体以创建两个或两个以上的实体,并且在一个实体中的更改会反映在其他实体中时,我们可以说我们已经进行了浅拷贝。在浅拷贝中,不会为其他实体进行新的内存分配,只会将引用复制到其他实体。以下示例演示了这一点。

文件名: ShallowCopyExample.java

输出

The value of x is: 6

说明: 在上面的示例中,我们使用引用变量 obj2 更新 x 的值,并使用引用变量 obj1 显示 x 的值。在输出中,我们看到更新后的值 6,而不是原始值 30。这是因为 obj1 和 obj2 指向相同的内存位置。因此,无论我们使用引用变量 obj2 进行什么更新,使用引用变量 obj1 都会反映相同的更改。

深拷贝

当我们复制某个实体以创建两个或两个以上的实体,并且在一个实体中的更改不会反映在其他实体中时,我们可以说我们已经进行了深拷贝。在深拷贝中,会为其他实体进行新的内存分配,并且不会将引用复制到其他实体。每个实体都有自己的独立引用。以下示例演示了这一点。

文件名: DeepCopyExample.java

输出

The value of x is: 30

说明: 在上面的示例中,我们使用引用变量 obj2 更新 x 的值,并使用引用变量 obj1 显示 x 的值。在输出中,我们看到原始值 30,而不是更新后的值 6。这是因为 obj1 和 obj2 指向不同的内存位置。因此,无论我们使用引用变量 obj2 进行什么更新,使用引用变量 obj1 都不会反映相同的更改。

浅拷贝与深拷贝的区别

在学习了浅拷贝和深拷贝之后,让我们看看它们之间的区别。

浅拷贝深拷贝
由于没有分配新内存,因此速度很快。由于分配了新内存,因此速度较慢。
在一个实体中的更改会反映在其他实体中。在一个实体中的更改不会影响其他实体中的更改。
clone() 方法的默认版本支持浅拷贝。为了使 clone() 方法支持深拷贝,必须重写 clone() 方法。
浅拷贝的开销较小。深拷贝的开销很大。
克隆对象和原始对象不是独立的。克隆对象和原始对象是独立的。

深拷贝和浅拷贝相似的场景

尽管深拷贝和浅拷贝之间存在差异,但在某些情况下,考虑拷贝是深拷贝还是浅拷贝没有意义。

在 String 中

让我们了解一下复制字符串时会发生什么。我们都知道字符串被认为是 java.lang 包中 String 类的对象。因此,与其他对象类似,当我们进行复制时,会复制引用。

文件名: StringCopyExample.java

输出

The hash code is: -2026030341
The hash code is: -2026030341

说明: 程序输出显示引用变量 obj1 和 obj2 显示的哈希码相同。这意味着引用变量 obj1 和 obj2 指向相同的内存位置。但是问题是,我们可以说我们上面的程序进行了浅拷贝吗?因为引用是相同的?答案是否定的。以下示例为我们提供了足够的证据来验证给出的答案。

文件名: StringCopyExample1.java

输出

The hash code is: -2026030341
The string is: JavaTpoint is a very good site.

The hash code is: 1724527163
The string is: JavaTpoint is very good.

说明: 程序输出告诉我们,引用变量 obj1 显示的哈希码不等于引用变量 obj2 显示的哈希码。此外,使用引用变量 obj2 所做的更改不会由引用变量 obj1 显示。这是因为Java 中的字符串始终是不可变的。因此,当 obj2 更改 obj1 的内容时,它最终会创建一个全新的字符串。因此,之前的字符串保持不变,引用变量 obj2 指向存储新字符串对象的新内存位置。

我们已经看到,字符串中的更改会导致隐式创建新的字符串对象。因此,复制字符串既不能称为深拷贝也不能称为浅拷贝。事实上,当我们处理 Java 中的字符串时,深拷贝和浅拷贝之间没有区别。

在原始数据类型中

让我们了解一下复制原始数据类型时会发生什么。与字符串不同,原始数据类型不是对象。但是,与字符串类似,在原始数据类型中也没有深拷贝或浅拷贝的概念。观察以下示例。

文件名: DataTypeCopyExample.java

输出

The value of x & y are: 9, 9
The value of x & y are: 9, 10
The value of b1 & b2 are: false, false
The value of b1 & b2 are: false, true

说明: 当 y 的值更新时,它不会影响 x 的值。这是因为 y 已经有了自己的内存分配。它并不指向 x 的内存位置。因此,语句 y = x; 仅将 x 的值复制到 y 中。因此,y 的任何更新都不会影响 x。类似的原理也适用于其他原始数据类型。在这里,y 和 b2 的内存分配是隐式发生的。

在 Java 中,没有规定何时使用浅拷贝和何时使用深拷贝。由程序员或开发人员决定他们想要使用什么。因此,建议了解需求,然后明智地在深拷贝和浅拷贝之间做出选择。

除了深拷贝和浅拷贝之外,还有一个术语叫做延迟拷贝。延迟拷贝实际上是深拷贝和浅拷贝的混合。在延迟拷贝中,在初始阶段使用浅拷贝。当修改原始内容时,程序通过计数器检查内容是否在其他对象之间共享。如果内容被共享,则应用深拷贝机制。


下一个主题Local-variable-in-java