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

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

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

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

(1)浅拷贝

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

(2)深拷贝

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

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

浅拷贝的情景:

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

深拷贝的情景:

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

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

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

2.浅拷贝的实现

       在Java中,实现浅拷贝通常使用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();
        }
    }
}

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

  1. 首先,我们定义了两个类:Person和Address。Person类有一个name属性和一个address属性,而Address类只有一个city属性。
  2. 在ShallowCopyExample类的main方法中,我们创建了一个Address对象,表示Alice的地址是"New York"。然后,我们创建了一个Person对象person1,传入了名字"Alice"和上面创建的Address对象。
  3. 接着,我们调用person1.clone()方法进行浅拷贝。由于Person类实现了Cloneable接口并重写了clone()方法,因此它支持克隆操作。在clone()方法内部,我们调用了super.clone()来复制Person对象本身,但是对于address属性,只是复制了其引用,而没有对Address对象进行深度复制。
  4. 输出语句System.out.println(person1.getAddress() == person2.getAddress());比较了person1和person2的address属性是否是同一个对象。由于浅拷贝只是复制了引用,所以person1和person2的address属性指向的是同一个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();
        }
    }
}

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

  1. Person 类和 Address 类都实现了 Cloneable 接口,这是为了表明它们可以被克隆。
  2. 在 Person 类中,有一个私有字段 address,类型为 Address。Person 类的构造函数用于初始化这个字段。
  3. Person 类的 clone() 方法首先调用了 super.clone(),这会复制 Person 对象本身。然后,它对 address 字段进行了深拷贝,即创建了一个新的 Address 对象,并将其赋值给 clonedPerson 的 address 字段。
  4. Address 类中的 clone() 方法也是调用了 super.clone(),实现了浅拷贝,因为 Address 类只有一个字段,且该字段为不可变类型。
  5. 在 main() 方法中,首先创建了一个 Address 对象和一个 Person 对象。然后,通过调用 clone() 方法,创建了一个新的 Person 对象 person2,其中包含了新的 Address 对象。
  6. 最后,通过比较 person1 和 person2 的地址字段,可以看到它们不相同,这表明在克隆过程中进行了深拷贝。

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

4.深浅拷贝的作用

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

浅拷贝的作用:

  1. 节省内存空间:浅拷贝只复制对象本身,不会复制对象引用的内容,因此在某些情况下可以节省内存空间。
  2. 提高对象创建速度:由于浅拷贝只复制对象本身,因此复制过程相对较快。
  3. 适用于不包含引用类型成员变量的对象:如果对象中的成员变量都是基本数据类型或者不需要被复制的对象,那么浅拷贝是一个简单有效的复制方式。

深拷贝的作用:

  1. 确保对象的独立性:深拷贝会递归地复制对象及其引用的所有对象,从而确保复制后的对象与原始对象完全独立,对复制对象的修改不会影响原始对象。
  2. 数据安全性:在多线程环境下,深拷贝可以确保对象的数据安全性,因为每个线程都可以操作独立的对象,而不会相互影响。
  3. 避免对象共享的副作用:在某些情况下,对象的共享可能会导致意外的副作用,深拷贝可以避免这种情况的发生,保证数据的一致性和可靠性。
  4. 适用于包含引用类型成员变量的对象:如果对象中包含了引用类型的成员变量,并且需要复制所有引用的对象,那么深拷贝是更合适的选择。

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

相关文章
|
4天前
|
Java
Java 中 `toList()` 与 `collect(Collectors.toList())` 的微妙差异:别再乱用了!
Java 中 `toList()` 与 `collect(Collectors.toList())` 的微妙差异:别再乱用了!
|
2月前
|
Java
深入JavaSE:详解Java对象的比较。
总的来说,Java对象的比较就像海洋生物的比较,有外在的,有内在的,有面对所有情况的,也有针对特殊情况的。理解并掌握这些比较方式,就能更好地驾驭Java的世界,游刃有余地操作Java对象。
59 12
|
3月前
|
编解码 JavaScript 前端开发
【Java进阶】详解JavaScript的BOM(浏览器对象模型)
总的来说,BOM提供了一种方式来与浏览器进行交互。通过BOM,你可以操作窗口、获取URL、操作历史、访问HTML文档、获取浏览器信息和屏幕信息等。虽然BOM并没有正式的标准,但大多数现代浏览器都实现了相似的功能,因此,你可以放心地在你的JavaScript代码中使用BOM。
115 23
|
3月前
|
Java 数据安全/隐私保护
Java 类和对象
本文介绍了Java编程中类和对象的基础知识,作为面向对象编程(OOP)的核心概念。类是对象的蓝图,定义实体类型;对象是具体实例,包含状态和行为。通过示例展示了如何创建表示汽车的类及其实例,并说明了构造函数、字段和方法的作用。同时,文章还探讨了访问修饰符的使用,强调封装的重要性,如通过getter和setter控制字段访问。最后总结了类与对象的关系及其在Java中的应用,并建议进一步学习继承等概念。
|
3月前
|
存储 缓存 Java
理解Java引用数据类型:它们都是对象引用
本文深入探讨了Java中引用数据类型的本质及其相关特性。引用变量存储的是对象的内存地址而非对象本身,类似房子的地址而非房子本身。文章通过实例解析了引用赋值、比较(`==`与`equals()`的区别)以及包装类缓存机制等核心概念。此外,还介绍了Java引用类型的家族,包括类、接口、数组和枚举。理解这些内容有助于开发者避免常见错误,提升对Java内存模型的掌握,为高效编程奠定基础。
159 0
|
10月前
|
存储 Java
Java编程中的对象和类
【8月更文挑战第55天】在Java的世界中,“对象”与“类”是构建一切的基础。就像乐高积木一样,类定义了形状和结构,而对象则是根据这些设计拼装出来的具体作品。本篇文章将通过一个简单的例子,展示如何从零开始创建一个类,并利用它来制作我们的第一个Java对象。准备好让你的编程之旅起飞了吗?让我们一起来探索这个神奇的过程!
72 10
|
10月前
|
存储 Java
Java的对象和类的相同之处和不同之处
在 Java 中,对象和类是面向对象编程的核心。
114 18
【Java】— —实现人物对象的增、删、改、查(注:对象的删除以逻辑删除为主,在person类中设置“删除状态字段”,字删除该字段时,将状态改为有效。)
【Java】— —实现人物对象的增、删、改、查(注:对象的删除以逻辑删除为主,在person类中设置“删除状态字段”,字删除该字段时,将状态改为有效。)
|
10月前
|
Java
Java 对象和类
在Java中,**类**(Class)和**对象**(Object)是面向对象编程的基础。类是创建对象的模板,定义了属性和方法;对象是类的实例,通过`new`关键字创建,具有类定义的属性和行为。例如,`Animal`类定义了`name`和`age`属性及`eat()`、`sleep()`方法;通过`new Animal()`创建的`myAnimal`对象即可调用这些方法。面向对象编程通过类和对象模拟现实世界的实体及其关系,实现问题的结构化解决。
67 4
|
11月前
|
机器学习/深度学习 人工智能 算法
探索人工智能在医疗诊断中的应用与挑战Java编程中的对象和类:基础与实践
【8月更文挑战第27天】随着人工智能(AI)技术的飞速发展,其在医疗领域的应用日益广泛。本文深入探讨了AI技术在医疗诊断中的具体应用案例,包括图像识别、疾病预测和药物研发等方面,并分析了当前面临的主要挑战,如数据隐私、算法偏见和法规限制等。文章旨在为读者提供一个全面的视角,理解AI在改善医疗服务质量方面的潜力及其局限性。

热门文章

最新文章