“深入探讨Java中的对象拷贝:浅拷贝与深拷贝的差异与应用“

秋刀鱼不做梦 2024-07-27 15:05:08 阅读 57

        前言:在Java编程中,深拷贝(Deep Copy)与浅拷贝(Shallow Copy)是两个非常重要的概念。它们涉及到对象在内存中的复制方式,对于理解对象的引用、内存管理以及数据安全都至关重要。


✨✨✨这里是秋刀鱼不做梦的BLOG

✨✨✨想要了解更多内容可以访问我的主页秋刀鱼不做梦-CSDN博客

先让我们看一下本文的大致内容:

目录

1.深拷贝与浅拷贝的概念

(1)浅拷贝

(2)深拷贝

2.浅拷贝的实现

3.深拷贝的实现

4.深浅拷贝的作用

浅拷贝的作用:

深拷贝的作用:


1.深拷贝与浅拷贝的概念

        ——在了解Java中是如何实现对象的深浅拷贝之前,我们需要先了解一下什么是深拷贝、浅拷贝:

(1)浅拷贝

        在浅拷贝中,只复制对象本身,而不复制对象引用的内容。这意味着,如果对象中包含了引用类型的成员变量,那么这些成员变量的引用将会被复制,但是它们仍然指向相同的内存地址。因此,对于引用类型成员变量的修改会影响到原始对象和拷贝对象。

(2)深拷贝

        与浅拷贝不同,深拷贝会递归地复制对象及其所有引用的对象,直到所有对象都被复制到一个新的内存地址上。这样,原始对象和拷贝对象完全独立,彼此的修改不会相互影响。

        嗯嗯嗯......感觉看了和没看没什么区别,还是不太能理解到底什么是Java中的深浅拷贝,那么我们使用一个生活中的案例来解释一下:

浅拷贝的情景:

        ——如果你选择了浅拷贝,那么你会简单地把整个礼物篮进行复制,然后送给你的朋友。在这种情况下,你的朋友会得到一个看起来一模一样的礼物篮。然而,当你的朋友拆开礼物篮,他们发现里面的食品和饰品并没有改变,他们是和你的礼物篮里的相同的食品和饰品。

深拷贝的情景:

        ——相比之下,如果你选择了深拷贝,那么你会仔细地把礼物篮里的每一样东西都复制一份,然后把这些复制品装进一个新的礼物篮里,送给你的朋友。在这种情况下,你的朋友得到的是一个全新的礼物篮,里面的食品和饰品和你的礼物篮里的完全一样。但是,现在他们拥有的是独立于你的礼物篮的新的食品和饰品。

不知道上面的生活案例有没有使你更好的理解Java中的深浅拷贝,如果还是没有,那么直接往下看即可!

大致的了解了什么是Java中的深浅拷贝之后,那么我们又该如何使用代码去实现它们呢?

2.浅拷贝的实现

        在Java中,实现浅拷贝通常使用<code>clone()方法。该方法会创建一个新对象,并将原始对象的所有字段值复制到新对象中。但是需要注意的是,对于引用类型的成员变量,仍然是浅拷贝,即复制的是引用而不是对象本身。

        下面是在Java中实现浅拷贝的详细步骤:

1.实现Cloneable接口:

class MyClass implements Cloneable {

// 类的定义

}

 2.重写clone()方法并调用super.clone()

class MyClass implements Cloneable {

// 类的定义

@Override

public Object clone() throws CloneNotSupportedException {

return super.clone();

}

}

3.在使用时捕获CloneNotSupportedException异常:

try {

MyClass copy = (MyClass) original.clone();

} catch (CloneNotSupportedException e) {

e.printStackTrace();

}

4.强制转换:由于clone()方法返回的是Object类型,因此在使用时需要进行类型转换。

try {

MyClass copy = (MyClass) original.clone();

} catch (CloneNotSupportedException e) {

e.printStackTrace();

}

       

         这就是实现Java中浅拷贝的四步实现流程,相信你仔细的读完上边的代码之后,对Java中浅拷贝的实现流程已经有了初步的理解了,现在让我们使用一个完整的案例,来实现一下Java中的浅拷贝:    

class Person implements Cloneable {

private String name;

private Address address;

public Person(String name, Address address) {

this.name = name;

this.address = address;

}

// Getter and setter 方法

@Override

protected Object clone() throws CloneNotSupportedException {

return super.clone();

}

}

class Address {

private String city;

public Address(String city) {

this.city = city;

}

// Getter and setter 方法

}

public class ShallowCopyExample {

public static void main(String[] args) {

Address address = new Address("New York");

Person person1 = new Person("Alice", address);

try {

Person person2 = (Person) person1.clone();

// 输出: true

System.out.println(person1.getAddress() == person2.getAddress());

} catch (CloneNotSupportedException e) {

e.printStackTrace();

}

}

}

以上代码演示了一个浅拷贝的例子。让我来解释一下它的执行过程和输出:

首先,我们定义了两个类:PersonAddressPerson类有一个name属性和一个address属性,而Address类只有一个city属性。

ShallowCopyExample类的main方法中,我们创建了一个Address对象,表示Alice的地址是"New York"。然后,我们创建了一个Person对象person1,传入了名字"Alice"和上面创建的Address对象。

接着,我们调用person1.clone()方法进行浅拷贝。由于Person类实现了Cloneable接口并重写了clone()方法,因此它支持克隆操作。在clone()方法内部,我们调用了super.clone()来复制Person对象本身,但是对于address属性,只是复制了其引用,而没有对Address对象进行深度复制。

输出语句System.out.println(person1.getAddress() == person2.getAddress());比较了person1person2address属性是否是同一个对象。由于浅拷贝只是复制了引用,所以person1person2address属性指向的是同一个Address对象,因此输出结果为true

这样我们就大致的了解了在Java中如何去实现对象的浅拷贝了。

3.深拷贝的实现

        在Java中实现深拷贝相对于浅拷贝来说更为复杂,因为需要确保对象及其引用的所有对象都被复制到新的内存地址上。

        下面是在Java中实现深拷贝的详细流程:

1.实现Cloneable接口:同样,为了使用clone()方法,需要确保类实现了Cloneable接口。

class MyClass implements Cloneable {

// 类的定义

}

2.重写clone()方法:在重写的clone()方法中,除了调用super.clone()来复制对象本身之外,还需要递归地复制所有引用的对象。

class MyClass implements Cloneable {

private AnotherClass anotherObject;

public MyClass(AnotherClass anotherObject) {

this.anotherObject = anotherObject;

}

// Getter and setter 方法

@Override

public Object clone() throws CloneNotSupportedException {

MyClass clonedObject = (MyClass) super.clone();

// 对引用类型的成员变量进行深度复制

clonedObject.anotherObject = (AnotherClass) anotherObject.clone();

return clonedObject;

}

}

3.在引用类型的类中同样实现深拷贝:如果类中有成员变量是引用类型,那么需要在该引用类型的类中同样实现深拷贝。

class AnotherClass implements Cloneable {

// 类的定义

@Override

public Object clone() throws CloneNotSupportedException {

return super.clone();

}

}

4.调用clone()方法:现在可以调用clone()方法来获取深拷贝的对象。

public class DeepCopyExample {

public static void main(String[] args) {

AnotherClass anotherObject = new AnotherClass();

MyClass original = new MyClass(anotherObject);

MyClass deepCopy = null;

try {

deepCopy = (MyClass) original.clone();

} catch (CloneNotSupportedException e) {

e.printStackTrace();

}

}

}

        这就是实现Java中深拷贝的四步实现流程,当然,现在让我们使用一个完整的案例,来实现一下Java中的深拷贝:    

class Person implements Cloneable {

private String name;

private Address address;

public Person(String name, Address address) {

this.name = name;

this.address = address;

}

// Getter and setter 方法

@Override

protected Object clone() throws CloneNotSupportedException {

Person clonedPerson = (Person) super.clone();

clonedPerson.address = (Address) this.address.clone();

return clonedPerson;

}

}

class Address implements Cloneable {

private String city;

public Address(String city) {

this.city = city;

}

// Getter and setter 方法

@Override

protected Object clone() throws CloneNotSupportedException {

return super.clone();

}

}

public class DeepCopyExample {

public static void main(String[] args) {

Address address = new Address("New York");

Person person1 = new Person("Alice", address);

try {

Person person2 = (Person) person1.clone();

// 输出: false

System.out.println(person1.getAddress() == person2.getAddress());

} catch (CloneNotSupportedException e) {

e.printStackTrace();

}

}

}

让我解释一下代码的主要部分:

Person 类和 Address 类都实现了 Cloneable 接口,这是为了表明它们可以被克隆。

Person 类中,有一个私有字段 address,类型为 AddressPerson 类的构造函数用于初始化这个字段。

Person 类的 clone() 方法首先调用了 super.clone(),这会复制 Person 对象本身。然后,它对 address 字段进行了深拷贝,即创建了一个新的 Address 对象,并将其赋值给 clonedPersonaddress 字段。

Address 类中的 clone() 方法也是调用了 super.clone(),实现了浅拷贝,因为 Address 类只有一个字段,且该字段为不可变类型。

main() 方法中,首先创建了一个 Address 对象和一个 Person 对象。然后,通过调用 clone() 方法,创建了一个新的 Person 对象 person2,其中包含了新的 Address 对象。

最后,通过比较 person1person2 的地址字段,可以看到它们不相同,这表明在克隆过程中进行了深拷贝。

这样我们就大致的了解了在Java中如何去实现对象的深拷贝了。

4.深浅拷贝的作用

        了解完了Java中的深浅拷贝之后,那么其有什么用呢?

浅拷贝的作用:

节省内存空间:浅拷贝只复制对象本身,不会复制对象引用的内容,因此在某些情况下可以节省内存空间。

提高对象创建速度:由于浅拷贝只复制对象本身,因此复制过程相对较快。

适用于不包含引用类型成员变量的对象:如果对象中的成员变量都是基本数据类型或者不需要被复制的对象,那么浅拷贝是一个简单有效的复制方式。

深拷贝的作用:

确保对象的独立性:深拷贝会递归地复制对象及其引用的所有对象,从而确保复制后的对象与原始对象完全独立,对复制对象的修改不会影响原始对象。

数据安全性:在多线程环境下,深拷贝可以确保对象的数据安全性,因为每个线程都可以操作独立的对象,而不会相互影响。

避免对象共享的副作用:在某些情况下,对象的共享可能会导致意外的副作用,深拷贝可以避免这种情况的发生,保证数据的一致性和可靠性。

适用于包含引用类型成员变量的对象:如果对象中包含了引用类型的成员变量,并且需要复制所有引用的对象,那么深拷贝是更合适的选择。

        总的来说,浅拷贝适用于简单对象的复制,可以提高性能和节省内存空间,而深拷贝则适用于需要确保对象独立性和数据安全性的情况,尤其是当对象包含引用类型成员变量时。


以上就是本篇文章的全部内容了~~~



声明

本文内容仅代表作者观点,或转载于其他网站,本站不以此文作为商业用途
如有涉及侵权,请联系本站进行删除
转载本站原创文章,请注明来源及作者。