iis服务器助手广告广告
返回顶部
首页 > 资讯 > 后端开发 > Python >Java的深拷贝和浅拷贝深入了解
  • 845
分享到

Java的深拷贝和浅拷贝深入了解

2024-04-02 19:04:59 845人浏览 八月长安

Python 官方文档:入门教程 => 点击学习

摘要

关于Java的深拷贝和浅拷贝,简单来说就是创建一个和已知对象一模一样的对象。可能日常编码过程中用的不多,但是这是一个面试经常会问的问题,而且了解深拷贝和浅拷贝的原理,对于Java中的

关于Java的深拷贝和浅拷贝,简单来说就是创建一个和已知对象一模一样的对象。可能日常编码过程中用的不多,但是这是一个面试经常会问的问题,而且了解深拷贝和浅拷贝的原理,对于Java中的所谓值传递或者引用传递将会有更深的理解。

1、创建对象的5种方式

①、通过 new 关键字

这是最常用的一种方式,通过 new 关键字调用类的有参或无参构造方法来创建对象。比如 Object obj = new Object();

②、通过 Class 类的 newInstance() 方法

这种默认是调用类的无参构造方法创建对象。比如Person p2 = (Person) Class.forName("com.ys.test.Person").newInstance();

③、通过Constructor 类的 newInstance 方法

这和第二种方法类时,都是通过反射来实现。通过java.lang.relect.Constructor 类的newInstance() 方法指定某个构造器来创建对象。

Person p3 = (Person) Person.class.getConstructors()[0].newInstance();

实际上第二种方法利用 Class 的 newInstance() 方法创建对象,其内部调用还是 Constructor 的 newInstance() 方法。

④、利用 Clone 方法

Clone 是 Object 类中的一个方法,通过 对象A.clone() 方法会创建一个内容和对象 A 一模一样的对象 B,clone 克隆,顾名思义就是创建一个一模一样的对象出来。

Person p4 = (Person) p3.clone();

⑤、反序列化

序列化是把堆内存中的 Java 对象数据,通过某种方式把对象存储到磁盘文件中或者传递给其他网络节点(在网络上传输)。而反序列化则是把磁盘文件中的对象数据或者把网络节点上的对象数据,恢复成Java对象模型的过程。

具体如何实现可以参考我这篇博文。

2、Clone 方法

本篇博客我们讲解的是 Java 的深拷贝和浅拷贝,其实现方式正是通过调用 Object 类的 clone() 方法来完成。在 Object.class 类中,源码为:

protected native Object clone() throws CloneNotSupportedException;

这是一个用 native 关键字修饰的方法,关于native关键字有一篇博客专门有介绍,不理解也没关系,只需要知道用 native 修饰的方法就是告诉操作系统,这个方法我不实现了,让操作系统去实现。具体怎么实现我们不需要了解,只需要知道 clone方法的作用就是复制对象,产生一个新的对象。那么这个新的对象和原对象是什么关系呢?

3、基本类型和引用类型

这里再给大家普及一个概念,在 Java 中基本类型和引用类型的区别。

在 Java 中数据类型可以分为两大类:基本类型和引用类型。

基本类型也称为值类型,分别是字符类型 char,布尔类型 boolean以及数值类型 byteshortintlongfloatdouble

引用类型则包括类、接口、数组、枚举等。

Java 将内存空间分为堆和栈。基本类型直接在栈中存储数值,而引用类型是将引用放在栈中,实际存储的值是放在堆中,通过栈中的引用指向堆中存放的数据。  

上图定义的 a 和 b 都是基本类型,其值是直接存放在栈中的;而 c 和 d 是 String 声明的,这是一个引用类型,引用地址是存放在 栈中,然后指向堆的内存空间。

下面 d = c;这条语句表示将 c 的引用赋值给 d,那么 c 和 d 将指向同一块堆内存空间。

4、浅拷贝

我们看如下这段代码:

package com.ys.test;
public class Person implements Cloneable{
    public String pname;
    public int page;
    public Address address;
    public Person() {}
    public Person(String pname,int page){
        this.pname = pname;
        this.page = page;
        this.address = new Address();
    }
    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
    public void setAddress(String provices,String city ){
        address.setAddress(provices, city);
    }
    public void display(String name){
        System.out.println(name+":"+"pname=" + pname + ", page=" + page +","+ address);
    }
    public String getPname() {
        return pname;
    }
    public void setPname(String pname) {
        this.pname = pname;
    }
    public int getPage() {
        return page;
    }
    public void setPage(int page) {
        this.page = page;
    }
}
package com.ys.test;
public class Address {
    private String provices;
    private String city;
    public void setAddress(String provices,String city){
        this.provices = provices;
        this.city = city;
    }
    @Override
    public String toString() {
        return "Address [provices=" + provices + ", city=" + city + "]";
    }
}

这是一个我们要进行赋值的原始类 Person。下面我们产生一个 Person 对象,并调用其 clone 方法复制一个新的对象。

注意:调用对象的 clone 方法,必须要让类实现Cloneable 接口,并且覆写 clone 方法。

测试:

@Test
public void testShallowClone() throws Exception{
    Person p1 = new Person("zhangsan",21);
    p1.setAddress("湖北省", "武汉市");
    Person p2 = (Person) p1.clone();
    System.out.println("p1:"+p1);
    System.out.println("p1.getPname:"+p1.getPname().hashCode());
    System.out.println("p2:"+p2);
    System.out.println("p2.getPname:"+p2.getPname().hashCode());
    p1.display("p1");
    p2.display("p2");
    p2.setAddress("湖北省", "荆州市");
    System.out.println("将复制之后的对象地址修改:");
    p1.display("p1");
    p2.display("p2");
}

打印结果为:

首先看原始类 Person 实现Cloneable 接口,并且覆写 clone 方法,它还有三个属性,一个引用类型 String定义的 pname,一个基本类型 int定义的 page,还有一个引用类型 Address ,这是一个自定义类,这个类也包含两个属性 pprovices 和 city 。

接着看测试内容,首先我们创建一个Person 类的对象 p1,其pname 为zhangsan,page为21,地址类 Address 两个属性为 湖北省和武汉市。接着我们调用 clone() 方法复制另一个对象 p2,接着打印这两个对象的内容。

从第 1 行和第 3 行打印结果:

p1:com.ys.test.Person@349319f9

p2:com.ys.test.Person@258e4566

可以看出这是两个不同的对象。

从第 5 行和第 6 行打印的对象内容看,原对象 p1 和克隆出来的对象 p2 内容完全相同。

代码中我们只是更改了克隆对象 p2 的属性 Address 为湖北省荆州市(原对象 p1 是湖北省武汉市) ,但是从第 7 行和第 8 行打印结果来看,原对象 p1 和克隆对象 p2 的 Address 属性都被修改了。

也就是说对象 Person 的属性 Address,经过 clone 之后,其实只是复制了其引用,他们指向的还是同一块堆内存空间,当修改其中一个对象的属性 Address,另一个也会跟着变化。  

浅拷贝:创建一个新对象,然后将当前对象的非静态字段复制到该新对象,如果字段是值类型的,那么对该字段执行复制;如果该字段是引用类型的话,则复制引用但不复制引用的对象。因此,原始对象及其副本引用同一个对象。

5、深拷贝

弄清楚了浅拷贝,那么深拷贝就很容易理解了。

深拷贝:创建一个新对象,然后将当前对象的非静态字段复制到该新对象,无论该字段是值类型的还是引用类型,都复制独立的一份。当你修改其中一个对象的任何内容时,都不会影响另一个对象的内容。

那么该如何实现深拷贝呢?Object 类提供的 clone 是只能实现 浅拷贝的。

6、如何实现深拷贝?

深拷贝的原理我们知道了,就是要让原始对象和克隆之后的对象所具有的引用类型属性不是指向同一块堆内存,这里有三种实现思路。

①、让每个引用类型属性内部都重写clone() 方法

既然引用类型不能实现深拷贝,那么我们将每个引用类型都拆分为基本类型,分别进行浅拷贝。比如上面的例子,Person 类有一个引用类型 Address(其实String 也是引用类型,但是String类型有点特殊,后面会详细讲解),我们在 Address 类内部也重写 clone 方法。如下:

Address.class:

package com.ys.test;
public class Address implements Cloneable{
    private String provices;
    private String city;
    public void setAddress(String provices,String city){
        this.provices = provices;
        this.city = city;
    }
    @Override
    public String toString() {
        return "Address [provices=" + provices + ", city=" + city + "]";
    }
    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
}

Person.class 的 clone() 方法:

@Override
    protected Object clone() throws CloneNotSupportedException {
        Person p = (Person) super.clone();
        p.address = (Address) address.clone();
        return p;
    }

测试还是和上面一样,我们会发现更改了p2对象的Address属性,p1 对象的 Address 属性并没有变化。

但是这种做法有个弊端,这里我们Person 类只有一个 Address 引用类型,而 Address 类没有,所以我们只用重写 Address 类的clone 方法,但是如果 Address 类也存在一个引用类型,那么我们也要重写其clone 方法,这样下去,有多少个引用类型,我们就要重写多少次,如果存在很多引用类型,那么代码量显然会很大,所以这种方法不太合适。

②、利用序列化

序列化是将对象写到流中便于传输,而反序列化则是把对象从流中读取出来。这里写到流中的对象则是原始对象的一个拷贝,因为原始对象还存在 JVM 中,所以我们可以利用对象的序列化产生克隆对象,然后通过反序列化获取这个对象。

注意每个需要序列化的类都要实现Serializable 接口,如果有某个属性不需要序列化,可以将其声明为transient,即将其排除在克隆属性之外。

//深度拷贝
public Object deepClone() throws Exception{
    // 序列化
    ByteArrayOutputStream bos = new ByteArrayOutputStream();
    ObjectOutputStream oos = new ObjectOutputStream(bos);
    oos.writeObject(this);
    // 反序列化
    ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
    ObjectInputStream ois = new ObjectInputStream(bis);
    return ois.readObject();
}

因为序列化产生的是两个完全独立的对象,所有无论嵌套多少个引用类型,序列化都是能实现深拷贝的。

总结

本篇文章就到这里了,希望能够给你带来帮助,也希望您能够多多关注编程网的更多内容!

--结束END--

本文标题: Java的深拷贝和浅拷贝深入了解

本文链接: https://www.lsjlt.com/news/163024.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • Java的深拷贝和浅拷贝深入了解
    关于Java的深拷贝和浅拷贝,简单来说就是创建一个和已知对象一模一样的对象。可能日常编码过程中用的不多,但是这是一个面试经常会问的问题,而且了解深拷贝和浅拷贝的原理,对于Java中的...
    99+
    2022-11-13
  • js深拷贝和浅拷贝的深入讲解
    目录浅拷贝实现方法方法一:Object.assign方法二:扩展运算符方式方法三:concat和slice 浅拷贝数组深拷贝实现方法方法一:乞丐版(JSON.stringify和JS...
    99+
    2022-11-13
  • 深入理解python中的浅拷贝和深拷贝
    在讲什么是深浅拷贝之前,我们先来看这样一个现象: a = ['scolia', 123, [], ] b = a[:] b[2].append(666) print a print b 为什么我只对...
    99+
    2022-06-04
    和深 python
  • 浅拷贝&深拷贝
    浅拷贝新的对象指向原来对象的地址 深拷贝新的对象中,原来是可变对象,会新复制一份值指向新的地址[11,22,33]若原来的对象里含有可变对象,里面的这个可变对象也会指向新的地址['qwer', 123, [44,55]] 参考:https...
    99+
    2023-01-30
  • Java中浅拷贝和深拷贝详解
    目录Java浅拷贝深拷贝实现浅拷贝实现深拷贝Java浅拷贝深拷贝 浅拷贝和深拷贝涉及到了Object类中的clone()方法 实现浅拷贝 浅拷贝的实现需要类重写clone()方法 ...
    99+
    2022-11-12
  • python浅拷贝和深拷贝
    python中的赋值是按引用来传递的,如果不是赋值而是拷贝,那就需要用到copy模块了,这就不得不谈浅拷贝和深拷贝了。   浅拷贝copy()   #!/usr/bin/python  import copy  class MyClass:...
    99+
    2023-01-31
    和深 python
  • 浅拷贝与深拷贝
       名词解释 1.对象:被分配的一块内存,存储其所代表的值 2.引用:是自动形成的从变量到对象的指针 3.注意:类型(int类型,long类型(python3已去除long类型,只剩下int类型的数据))属于对象,不是变量 4.不可变...
    99+
    2023-01-30
  • python深拷贝浅拷贝
    python深拷贝和浅拷贝问题:   什么是深拷贝?     (个人理解)深拷贝就是将原有的数据一模一样的拷贝一份,然后存到另一个地址中,而不是引用地址   什么是浅拷贝?     (个人理解)就是引用地址 (1)用等于号的拷贝都属于浅拷...
    99+
    2023-01-30
    python
  • 浅谈JavaScript浅拷贝和深拷贝
    目录一、直接赋值二、浅拷贝三、深拷贝1. JSON对象的方式2. 递归复制网上关于这个话题,讨论有很多了,根据各路情况我自己整理了一下,最后还是能接近完美的实现深拷贝,欢迎大家讨论。...
    99+
    2022-11-12
  • java中的浅拷贝与深拷贝
    1、什么叫Java浅拷贝?浅拷贝是会将对象的每个属性进行依次复制,但是当对象的属性值是引用类型时,实质复制的是其引用,当引用指向的值改变时也会跟着变化。2、什么叫Java深拷贝?深拷贝复制变量值,对于引用数据,则递归至基本类型后,再复制。深...
    99+
    2021-10-17
    java教程 java 浅拷贝 深拷贝
  • java对象拷贝之深拷贝与浅拷贝
    要实现对象拷贝必须实现一个Cloneable接口,如果不实现这个接口就会产生一个CloneNotSupportedException异常。其实这个接口一个方法都没有,因此这类接口常被称作标记接口。Object 中有一个clone() 方法实...
    99+
    2016-12-31
    java入门 java 对象 深拷贝 浅拷贝
  • 什么是Java浅拷贝和深拷贝
    这篇文章主要讲解了“什么是Java浅拷贝和深拷贝”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“什么是Java浅拷贝和深拷贝”吧!问题“如果你有一个对象, 并...
    99+
    2022-10-19
  • python深拷贝与浅拷贝
    可变对象与不可变对象 要理解深拷贝和浅拷贝,首先要理解可变对象和不可变对象。 不可变对象:该对象所指向的内存中的值不能被改变,修改对象的值时,由于其指向的值不能被改变,因此实际上是在内存中重新开辟一个地址用来存储新的值,然后将对象指向这个...
    99+
    2023-01-30
    python
  • 浅拷贝和深拷贝的区别
    浅拷贝,指的是重新分配一块内存,创建一个新的对象,但里面的元素是原对象中各个子对象的引用。 2、深拷贝,是指重新分配一块内存,创建一个新的对象,并且将原对象中的元素,以递归的方式,通过创建新的子对象拷贝到新对象中。因此,新对象和原对象没有任...
    99+
    2023-09-21
    python
  • Python中的深拷贝浅拷贝
    什么是浅拷贝,什么是深拷贝? 一、浅拷贝 浅拷贝就是:拷贝了引用,并没有拷贝内容,和在Linux中的硬链接有些类似,在python中,使用=赋值的动作就是一个浅拷贝 浅拷贝中的新旧对象,共用一个内存地...
    99+
    2023-09-08
    python 开发语言
  • 什么是深拷贝和浅拷贝
    深拷贝和浅拷贝分别是指:深拷贝是指拷贝对象的具体内容,二内存地址是自主分配的,拷贝结束之后俩个对象虽然存的值是一样的,但是内存地址不一样,俩个对象页互相不影响,互不干涉。浅拷贝是指对内存地址的复制,让目标对象指针和源对象指向同一片内存空间。...
    99+
    2023-10-29
  • 分析JavaScript浅拷贝和深拷贝
    本篇内容主要讲解“分析JavaScript浅拷贝和深拷贝”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“分析JavaScript浅拷贝和深拷贝”吧!一、直接赋值对象是引用类型,如果直接赋值给另外一...
    99+
    2023-06-25
  • C++的深浅拷贝和写时拷贝你了解吗
    目录1.浅拷贝2.深拷贝3.引用计数+写时拷贝总结1.浅拷贝 浅拷贝:对于有申请空间的对象的类来说,是按照字节序依次拷贝过去的,并没有另外申请一块空间。因此,在调用析构函数的时候会造...
    99+
    2022-11-13
  • JavaScript深拷贝与浅拷贝原理深入探究
    目录一、JS中数据的存储形式-堆栈二、深浅拷贝的三种方式遍历赋值Object.create()遍历赋值实现深拷贝一、JS中数据的存储形式-堆栈 我们先简单理解一下堆栈分别是啥: 什么...
    99+
    2022-11-13
    JS 深拷贝 浅拷贝 JS 深拷贝 JS 浅拷贝
  • 怎么理解python指针拷贝,浅拷贝和深拷贝
    本篇内容主要讲解“怎么理解python指针拷贝,浅拷贝和深拷贝”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“怎么理解python指针拷贝,浅拷贝和深拷贝”吧!首先对于不可变类型int,strin...
    99+
    2023-06-02
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作