Java基础---传递拷贝

news2024/11/26 18:41:03

目录

Java是值传递还是引用传递

什么是深拷贝和浅拷贝

浅拷贝案例解析

BeanUtils的浅拷贝

实现深拷贝

深拷贝案例解析


  • Java是值传递还是引用传递

  • 编程语言中需要进行方法间的参数传递,这个传递的策略叫做求值策略
  • 在程序设计中,求值策略有很多种,比较常见的就是值传递和引用传递
  • 按值调用(call by value)表示方法接收的是调用者提供的值
  • 而按引用调用(call byreference)表示方法接收的是调用者提供的变量地址
  • 一个方法可以修改传递引用所对应的变量值,而不能修改传递值调用所对应的变量值
  • 值传递和引用传递最大的区别是传递的过程中有没有复制出一个副本来,如果是传递副本,那就是值传递,否则就是引用传递
  • Java只有值传递
  • Java对象的传递,是通过复制的方式把引用关系传递了,因为有复制的过程,所以是值传递,只不过对于Java对象的传递,传递的内容是对象的引用
  • 什么是深拷贝和浅拷贝

  • 在计算机内存中,每个对象都有一个地址,这个地址指向对象在内存中存储的位置
  • 当使用变量引用一个对象时,实际上是将该对象的地址赋值给变量
  • 因此如果将一个对象复制到另一个变量中,实际上是将对象的地址复制到了这个变量中
  • 浅拷贝——拷贝的太“浅”了,只拷贝对象引用,即对象的地址
  • 浅拷贝是指将一个对象复制到另一个变量中,但是只复制对象的地址,而不是对象本身
  • 也就是说,原始对象和复制对象实际上是共享同一个内存地址的
  • 因此如果修改了复制对象中的属性或元素,原始对象中对应的属性或元素也会被修改

  • 在Java中常用的各种BeanUtils基本也都是浅拷贝的
  • 深拷贝——拷贝的很“深”,复制对象的值到新开辟的空间,副本和原来的值没有任何耦合,真正意义的‘拷贝’
  • 深拷贝是指将一个对象及其所有子对象都复制到另一个变量中,也就是说,它会创建一个全新的对象,并将原始对象中的所有属性或元素都复制到新的对象中
  • 因此如果修改复制对象中的属性或元素,原始对象中对应的属性或元素不会受到影响

  • 浅拷贝案例解析

  • 定义:
  • 基本数据类型:short,int,long,float,double,char,byte,boolean
  • 特殊类型:String(这个类型比较重要)
    • String 存在于堆内存、常量池;这种比较特殊,本身没有实现 Cloneable,传递是引用地址
    • 由本身的final性,每次赋值都是一个新的引用地址,原对象的引用和副本的引用互不影响
    • 因此String就和基本数据类型一样,表现出了"深拷贝"特性
  • 代码以 学生背书包 为例,学生类Student,书包类Bag
  • 浅拷贝

  • 使用Clone()方法必须实现接口Cloneable,默认实现的就是浅拷贝(引用拷贝)

  • 看测试结果,一目了然

  • 运行如下:

  • BeanUtils的浅拷贝

  • 举个实际例子,来看下为啥前面说BeanUtils.copyProperties的过程是浅拷贝
  • 先来定义两个类:

  • 然后写一段测试代码:

  • 以上代码输出结果为:

  • 即,BeanUtils.copyProperties拷贝出来的newUser是一个新的对象,但是其中的address对象和原来的user中的address对象是同一个对象
  • 如果修改newUser中的Address对象的值的话,是会同时把user对象中的Address的值也修改了的
  • 可以尝试着修改下newUser中的address对象:

  • 输出结果:

  • 实现深拷贝

  • 如何实现深拷贝呢,主要有以下几个方法:
    • 实现Cloneable接口,重写clone()
      • 在Object类中定义了一个clone方法,这个方法其实在不重写的情况下,其实也是浅拷贝的
      • 如果想要实现深拷贝,就需要重写clone方法,而想要重写clone方法,就必须实现Cloneable,否则会报CloneNotSupportedException异常
      • 将上述代码修改下,重写clone方法:

      • 之后再执行一下上面的测试代码,就可以发现,这时候newUser中的address对象就是一个新的对象了
      • 这种方式就能实现深拷贝,但是问题是如果我们在User中有很多个对象,那么clone方法就写的很长,而且如果后面有修改,在User中新增属性,这个地方也要改
      • 那么有没有什么办法可以不需要修改,一劳永逸呢
    • 序列化实现深拷贝
      • 可以借助序列化来实现深拷贝
      • 先把对象序列化成流,再从流中反序列化成对象,这样就一定是新的对象了
      • 序列化的方式有很多,比如可以使用各种JSON工具,把对象序列化成JSON字符串,然后再从字符串中反序列化成对象
      • 如使用fastjson实现:

      • 也可实现深拷贝
      • 除此之外,还可以使用Apache Commons Lang中提供的SerializationUtils工具实现
      • 需要修改下上面的User和Address类,使他们实现Serializable接口,否则是无法进行序列化的

      • 然后在需要拷贝的时候:

      • 同样也可以实现深拷贝
  • 深拷贝案例解析

  • 实现Cloneable
    • 还是之前的Student和Bag类,可以看到在浅拷贝Student的时候,Bag是复合数据类型,浅拷贝的是这个Bag的引用,指向同一个地址
    • 那么深拷贝的话,同样需要将Bag复制一份到新的地址,实现Cloneable的类本身是进行深拷贝的,默认浅拷贝的方法是拷贝的该对象里面的复合数据类型,那么如果要将Student进行深拷贝,那么Bag也需要像Student一样实现Cloneable接口,并重写Clone()
    • 修改Bag.java

    • Bag也实现了Cloneable,那么在调用Student.clone()的时候,首先要使用Bag.clone()将bag的对象进行一次拷贝

    • 测试代码:

    • 测试结果如下:

    • 至此深拷贝和浅拷贝基本看完了
    • 但是如果Bag类型里面也含有复合数据类型呢?
    • 直接用上面的深拷贝代码,肯定是不行,不信看代码:
    • 假如学生背书包,书包里面有笔(钢笔、圆珠笔、铅笔...)

    • 测试代码:

    • 测试结果:

    • 由此看来直接这么做是无法完成深拷贝的,因为上述代码并不是完全的深拷贝,问题就出在书包Bag中的成员Pen

    • 既然发现了问题,那么要实现完全的深拷贝就简单了
    • 1.将Pen.java也实现cloneable接口,并且重写clone()
    • 2.在Bag.java中的clone()方法使用pen.clone()深拷贝一份到bag中的pen成员中
    • 问题又来了,如果Pen中又有一个复杂数据类型呢?
    • 岂不是又要将Pen中的复杂数据类型也要做同样的操作?
    • 是的,object的clone()方法,在深拷贝的时候,不适用于有对象多层嵌套的情况
  • 序列化
    • 上面已经暴露了简单使用clone()进行深拷贝的弊端,这里介绍另一种深拷贝的方式——序列化深拷贝
    • 所有bean必须实现 Serializable

    • 可以直接在Student中实现序列化【方法一】

    • 或者,直接将深拷贝方法包装成一个工具类【方法二:推荐该方法】:

    • 测试代码:

    • 测试结果如下:

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/750099.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【PHP面试题33】include和require的区别及用法

文章目录 一、前言二 、include和require的区别三、include和require的用法介绍3.1 include的用法3.2 require的用法及示例 四、include和require的用法示例4.1 包含文件4.2 包含文件并将结果赋值给变量4.3 动态包含文件4.4 使用绝对路径包含文件4.5 包含文件失败处理4.6 包含文…

数据库--->MySQL(1)【MySQL索引】

文章目录 MySQL的优点视图MySQL的存储过程与函数触发器MySQL的基本架构MySQL的引擎InnoDBMyISAM总结 索引什么是索引?索引的优缺点索引底层数据结构索引的分类创建索引的原则 MySQL的优点 MySQL 主要具有下面这些优点: 成熟稳定,功能完善。开…

分布式应用之Zookeeper和Kafka

分布式应用之Zookeeper和Kafka 一、Zookeeper 1.定义 分布式系统管理框架,主要用来解决分布式集群中应用系统的一致性问题 相当于各种分布式应用服务的 注册中心 文件系统 通知机制2.特点 (1)Zookeeper:一个领导者&#…

Qt| There‘s no Qtversion assigned to project... 解决方法

问题: 原因:相同工程在不同电脑下qt配置不一致导致,该项目qt setting设置有误。 解决方法:右键项目打开属性 找到Qt Project Settings->Qt Installation,切换到当前电脑所使用的qt版本即可。

【学习笔记】在Android使用Frida进行https抓包

最近需要在Android进行https抓包,对数据解密,找了很多方法,终于成功了,不过原文一些步骤对于我这个小白还是有点不理解的地方,在此记录一下。 1. 前提条件 一台root手机frida环境 2. frida环境搭建 该步骤全程参考&…

基于springboot或ssm的红色新闻系统

博主主页:猫头鹰源码 博主简介:Java领域优质创作者、CSDN博客专家、公司架构师、全网粉丝5万、专注Java技术领域和毕业设计项目实战 主要内容:毕业设计(Javaweb项目|小程序等)、简历模板、学习资料、面试题库、技术咨询 文末联系获取 项目介绍…

【已解决】VMware安装MacOS苹果虚拟机,开机后卡在苹果图标位置不动

我的计算机硬件与软件信息: Win11系统,VMware17,MacOS12 最近在VMware17上安装MacOS12苹果虚拟机时,前期所有内容都配置好之后,在开机时碰到了一个问题:开机后卡在苹果图标位置不动,即使等了一…

2023年Mac上有哪些优质的工具(一)

Downie 4 专门用来下载视频的,各大视频网站上的视频只要粘贴地址就可以直接下载,并且可以选择清晰度,再也不用受百度云的气了,下载速度非常快,让工作效率大大提高。 Xmind 大家熟知的一款思维导图软件,他…

day34-servlet 分页

0目录 servlet 1.分页 分页逻辑1:数据库中20条记录,要求每页5条数据,则一共有4页 分页逻辑2:数据库中21条记录,要求每页5条数据,则一共有5页 分页逻辑3:数据库中19条记录,要求每页…

pytorch构建深度网络的基本概念——随机梯度下降

文章目录 随机梯度下降定义一个简单的模型定义Loss什么是梯度随机梯度下降 随机梯度下降 现在说说深度学习中的权重更新算法:经典算法SGD:stochastic gradient descent,随机梯度下降。 定义一个简单的模型 假设我们的模型就是要拟合一根直…

基于深度学习的高精度课堂人脸检测系统(PyTorch+Pyside6+YOLOv5模型)

摘要:基于深度学习的高精度课堂人脸检测系统可用于日常生活中或野外来检测与定位课堂人脸目标,利用深度学习算法可实现图片、视频、摄像头等方式的课堂人脸目标检测识别,另外支持结果可视化与图片或视频检测结果的导出。本系统采用YOLOv5目标…

力扣876. 链表的中间结点

题目 给你单链表的头结点head,请你找出并返回链表的中间结点。如果有两个中间结点,则返回第二个中间结点。 题解 设置快慢指针slow和fast,slow每次走一步,fast每次走两步,当fast走完时,slow刚好指到链表中间…

Vue从小白到入门(保姆级教学)

文章目录 🍋Vue是什么?🍋MVVM思想 🍋vue2快速入门🍋注意事项 🍋数据单向渲染🍋数据双向渲染🍋作业布置 🍋事件绑定🍋事件处理机制🍋注意事项和细节&#x1f…

西门子S7300以太网模块labview软件介绍

借助捷米特ETH-S7300-JM01以太网模块,通过NetS7 OPC和NI OPC Servers,西门子S7-300与测控软件NI LABVIEW实现以太网通讯和监控。 功能简介 LabVIEW是一种程序开发环境,由美国国家仪器(NzI)公司研制开发,类…

Redis 宕机了,如何避免数据丢失?

前言 如果有人问你:"你会把 Redis 用在什么业务场景下?" 我想你大概率会说:"我会把它当作缓存使用,因为它把后端数据库中的数据存储在内存中,然后直接从内存中读取数据,响应速度会非常快。…

英华特在创业板上市:总市值约50亿元,国产品牌持续向上

7月13日,苏州英华特涡旋技术股份有限公司(下称“英华特”,SZ:301272)在深圳证券交易所创业板上市。本次上市,英华特的发行价为51.39元/股,发行数量为1463万股,募资总额约为7.52亿元,…

直播 | SDS 容灾方案,让制品数据更安全

近日,腾讯 CODING WePack 制品管理系统 V1 以及腾讯 CODING DevOps 研发效能管理平台 V7 与 XSKY 星辰天合的统一数据平台 XEDP 及天合翔宇分布式存储系统完成互相兼容认证,在数据层面满足了共同客户敏捷开发的高可用建设合规要求。 联合解决方案可以帮…

Linux stress命令---压力测试

一、使用场景 CPU压力测试 内存压力测试 磁盘IO测试 Swap可用性测试 二、语法及常用参数 stress [选项] [进程数] -?, --help:显示帮助信息 --version:显示版本信息 -v, --verbose:详细输出 -q, --quiet:静默输出 -t, --timeout&…

基于python 和anaconda搭建环境

目录 1.先了解以下几点。 2 方案:pycharmanaconda 3.基本步骤 4 熟悉anaconda。 4.1 虚拟环境的创建方法 4.2 anaconda prompt中,常用指令 4.3 在Anaconda Navigate中的一些操作 4.3.1给已有虚拟环境安装包 4.3.2 新建虚拟环境 4.4 在pycharm中…

JavaScript 深度剖析-函数式编程(一)

文章介绍 为什么要学习函数编程以及什么是函数式编程函数式编程的特性(纯函数、柯里化、函数组合等)函数式编程的应用场景函数式编程库 Lodash 为什么要学习函数式编程 函数式编程是非常古老的一个概念,早于第一台计算机的诞生,函数式编程的历史。 那…