我的编程空间,编程开发者的网络收藏夹
学习永远不晚

Spring学习笔记(一)【BeanUtils.copyProperties方法】

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

Spring学习笔记(一)【BeanUtils.copyProperties方法】

Spring下的BeanUtils.copyProperties方法是深拷贝还是浅拷贝?

一、浅拷贝深拷贝的理解


简单地说,拷贝就是将一个类中的属性拷贝到另一个中,对于BeanUtils.copyProperties来说,必须保证属性名和类型是相同的,因为它是根据get和set方法来赋值的

1、浅拷贝

浅拷贝对于基本数据类型就是直接进行值传递,在内存的另一个空间内存放,修改这个值不会影响到拷贝源的值
浅拷贝对于引用数据类型就是进行的是地址传递,并没有对该对象重新开辟一个内存空间进行存放,所以对于引用数据类型的浅拷贝就相当于两个引用指向了同一个内存地址

浅拷贝可以理解为如果是引用类型,那么目标对象拷贝的只是源对象的地址,无论目标对象还是源对象改变,他们都会一起改变

2、深拷贝

深拷贝就是将目标对象的属性全部复制一份给源对象,复制完之后他们就是隔开的,没有任何关系,无论操作源对象还是目标对象都对另一个没有影响

无论是浅拷贝还是深拷贝,对于基本类型和String来说都是没有影响的,有影响的只有引用类型数据

在这里插入图片描述

二、测试浅拷贝与深拷贝


  • 浅拷贝
package com.vinjcent;public class Main {    public static void main(String[] args) {        // 主人(正)        Master main = new Master("男");        // 宠物        Pet p = new Pet("小狗", 5);        main.setPet(p);        // 浅拷贝一个"主"对象(副)        Master vice = main.clone();        System.out.println("主对象: " + main);        System.out.println("副对象: " + vice);        System.out.println("拷贝后对象的指针是否都指向同一个堆内存: " + (main == vice));        System.out.println();        // 修改副对象中的性别属性        vice.setGender("女");        System.out.println("主对象: " + main);        System.out.println("副对象: " + vice);        System.out.println("修改拷贝对象中的String类型的属性gender后是否相同: " + main.getGender().equals(vice.getGender()));        System.out.println();        // 修改副对象中引用对象中的年龄属性        vice.getPet().setAge(10);        System.out.println("主对象: " + main);        System.out.println("副对象: " + vice);        System.out.println("修改拷贝对象中的引用类型Pet后,是否在同一个堆内存当中: " + (main.getPet() == vice.getPet()));        System.out.println();        System.out.println("可以发现,它是对'主'对象的拷贝,它不会拷贝'主'对象深层次的可变对象,只做第一层的拷贝");    }}// 宠物对象class Pet {    private String name;    private int age;    public Pet(String name, int age) {        this.name = name;        this.age = age;    }// ...省略set、get方法    @Override    public String toString() {        return "Pet{" +                "name='" + name + '\'' +                ", age=" + age +                '}';    }}// 主人对象class Master implements Cloneable {    private String gender;    private Pet pet;    public Master(String gender) {        this.gender = gender;    }// ...省略set、get方法    // 浅拷贝    @Override    public Master clone() {        try {            // TODO: copy mutable state here, so the clone can't change the internals of the original            return (Master) super.clone();        } catch (CloneNotSupportedException e) {            throw new AssertionError();        }    }    @Override    public String toString() {        return "Master{" +                "gender='" + gender + '\'' +                ", pet=" + pet +                '}';    }}
  • 输出结果

在这里插入图片描述

在这里插入图片描述

  • 深拷贝
package com.vinjcent;public class Main {    public static void main(String[] args) {        // 主人(正)        Master main = new Master("男");        // 宠物        Pet p = new Pet("小狗", 5);        main.setPet(p);        // 深拷贝一个"主"对象(副)        Master vice = main.clone();        System.out.println("主对象: " + main);        System.out.println("副对象: " + vice);        System.out.println("拷贝后对象的指针是否都指向同一个堆内存: " + (main == vice));        System.out.println();        // 修改副对象中的性别属性        vice.setGender("女");        System.out.println("主对象: " + main);        System.out.println("副对象: " + vice);        System.out.println("修改拷贝对象中的String类型的属性gender后是否相同: " + main.getGender().equals(vice.getGender()));        System.out.println();        // 修改副对象中引用对象中的年龄属性        vice.getPet().setAge(10);        System.out.println("主对象: " + main);        System.out.println("副对象: " + vice);        System.out.println("修改拷贝对象中的引用类型Pet后,是否在同一个堆内存当中: " + (main.getPet() == vice.getPet()));        System.out.println();        System.out.println("可以发现,它是对'主'对象的完全拷贝,无论是引用对象还是数组,都会拷贝一个新的对象,并且与源对象的引用完全隔离");    }}// 宠物对象class Pet implements Cloneable {    private String name;    private int age;    public Pet(String name, int age) {        this.name = name;        this.age = age;    }// ...省略set、get方法    @Override    public String toString() {        return "Pet{" +                "name='" + name + '\'' +                ", age=" + age +                '}';    }    // 浅拷贝    @Override    public Pet clone() {        try {            // TODO: copy mutable state here, so the clone can't change the internals of the original            return (Pet) super.clone();// 不同点        } catch (CloneNotSupportedException e) {            throw new AssertionError();        }    }}// 主人对象class Master implements Cloneable {    private String gender;    private Pet pet;    public Master(String gender) {        this.gender = gender;    }// ...省略set、get方法    // 深拷贝    @Override    public Master clone() {        try {            // TODO: copy mutable state here, so the clone can't change the internals of the original            Master master = (Master) super.clone();            master.pet = pet.clone();// 不同点            return master;        } catch (CloneNotSupportedException e) {            throw new AssertionError();        }    }    @Override    public String toString() {        return "Master{" +                "gender='" + gender + '\'' +                ", pet=" + pet +                '}';    }}
  • 输出结果

在这里插入图片描述

在这里插入图片描述

三、使用序列化实现深拷贝


什么是序列化? 把对象转换为字节序列的过程称为对象的序列化

什么是反序列化?把字节序列恢复为对象的过程称为对象的反序列化

为什么需要序列化?方便传输、存储,计算机数据传输是以字节为单位的,能处理所有类型的数据

通过序列化实现的拷贝不仅可以复制对象本身,而且可以复制其引用的成员对象,因此通过序列化将对象写到一个流中,再从流里将其读出来,可以实现深拷贝

实现序列化的对象其类必须实现Serializable接口

  • 代码演示
package com.vinjcent;import java.io.*;public class Main {    public static void main(String[] args) {        // 主人(正)        Master main = new Master("男");        // 宠物        Pet p = new Pet("小狗", 5);        main.setPet(p);        // 深拷贝一个"主"对象(副)        Master vice = main.clone();        System.out.println("主对象: " + main);        System.out.println("副对象: " + vice);        System.out.println("拷贝后对象的指针是否都指向同一个堆内存: " + (main == vice));        System.out.println();        // 修改副对象中的性别属性        vice.setGender("女");        System.out.println("主对象: " + main);        System.out.println("副对象: " + vice);        System.out.println("修改拷贝对象中的String类型的属性gender后是否相同: " + main.getGender().equals(vice.getGender()));        System.out.println();        // 修改副对象中引用对象中的年龄属性        vice.getPet().setAge(10);        System.out.println("主对象: " + main);        System.out.println("副对象: " + vice);        System.out.println("修改拷贝对象中的引用类型Pet后,是否在同一个堆内存当中: " + (main.getPet() == vice.getPet()));        System.out.println();        System.out.println("可以发现,它是对'主'对象的序列化实现完全拷贝,无论是引用对象还是数组,都会拷贝一个新的对象,并且与源对象的引用完全隔离");    }}// 宠物对象class Pet implements Serializable {    private String name;    private int age;    public Pet(String name, int age) {        this.name = name;        this.age = age;    }// ...省略set、get方法    @Override    public String toString() {        return "Pet{" +                "name='" + name + '\'' +                ", age=" + age +                '}';    }}// 主人对象class Master implements Serializable {    private String gender;    private Pet pet;    public Master(String gender) {        this.gender = gender;    }// ...省略set、get方法    public Master clone() {        ObjectOutputStream oos;        ObjectInputStream ois;        Master master = null;        ByteArrayOutputStream baos = new ByteArrayOutputStream();        try {            oos = new ObjectOutputStream(baos);            oos.writeObject(this);            // 将流序列化成对象            ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());            ois = new ObjectInputStream(bais);            master = (Master) ois.readObject();        } catch (IOException | ClassNotFoundException e) {            e.printStackTrace();        }        return master;    }    @Override    public String toString() {        return "Master{" +                "gender='" + gender + '\'' +                ", pet=" + pet +                '}';    }}
  • 输出结果

在这里插入图片描述

四、Spring下的BeanUtils.copyProperties()方法进行浅拷贝和深拷贝


对于BeanUtils.copyProperties来说,你必须保证属性名和类型是相同的,因为它是根据get和set方法来赋值的

但,BeanUtils只是浅拷贝

4.1 测试BeanUtils.copyProperties()浅拷贝

  • 代码演示
package com.vinjcent;import org.springframework.beans.BeanUtils;public class Main {    public static void main(String[] args) {        // 主人(正)        Master main = new Master("男");        // 宠物        Pet p = new Pet("小狗", 5);        main.setPet(p);        // 浅拷贝一个"主"对象(副)        Master vice = new Master();        BeanUtils.copyProperties(main, vice);   // 修改地方        System.out.println("主对象: " + main);        System.out.println("副对象: " + vice);        System.out.println("拷贝后对象的指针是否都指向同一个堆内存: " + (main == vice));        System.out.println();        // 修改副对象中的性别属性        vice.setGender("女");        System.out.println("主对象: " + main);        System.out.println("副对象: " + vice);        System.out.println("修改拷贝对象中的String类型的属性gender后是否相同: " + main.getGender().equals(vice.getGender()));        System.out.println();        // 修改副对象中引用对象中的年龄属性        vice.getPet().setAge(10);        System.out.println("主对象: " + main);        System.out.println("副对象: " + vice);        System.out.println("修改拷贝对象中的引用类型Pet后,是否在同一个堆内存当中: " + (main.getPet() == vice.getPet()));        System.out.println();    }}// 宠物对象class Pet {    private String name;    private int age;    public Pet(String name, int age) {        this.name = name;        this.age = age;    }// ...省略set、get方法    @Override    public String toString() {        return "Pet{" +                "name='" + name + '\'' +                ", age=" + age +                '}';    }}// 主人对象class Master {    private String gender;    private Pet pet;    public Master(String gender) {        this.gender = gender;    }    public Master() {}// ...省略set、get方法    @Override    public String toString() {        return "Master{" +                "gender='" + gender + '\'' +                ", pet=" + pet +                '}';    }}
  • 输出结果

在这里插入图片描述

4.2 测试BeanUtils.copyProperties()深拷贝

从上面提到,我们可以通过序列化的形式来实现bean的深拷贝,可在BeanUtils.copyProperties()方法中如何实现呢?

答:我们可以借助java8的一些stream新特性

  • 代码演示
package com.vinjcent;import org.springframework.beans.BeanUtils;import java.util.Arrays;import java.util.List;import java.util.stream.Collectors;public class Main {    public static void main(String[] args) {        // 要是用stream流,一般会使用到集合,先构造一个master集合        List<Master> main = Arrays.asList(new Master("男"), new Master("女"));        main = main.stream().map(m -> {            m.setPet(new Pet("源pet", 5));            return m;        }).collect(Collectors.toList());        // 使用stream流实现bean的深拷贝        List<Master> vice = main                .stream()                .map(m -> {                    Master temp = new Master();                    BeanUtils.copyProperties(m, temp);                    return temp;                }).collect(Collectors.toList());        System.out.println("主对象: " + main);        System.out.println("副对象: " + vice);        System.out.println("拷贝后对象的指针是否都指向同一个堆内存: " + (main == vice));        System.out.println();        // 修改副对象中第一个元素的性别属性        vice.get(0).setGender("女");        System.out.println("主对象: " + main);        System.out.println("副对象: " + vice);        System.out.println("在拷贝对象中,修改第一个元素的String类型的属性gender后是否相同: " + main.get(0).getGender().equals(vice.get(0).getGender()));        System.out.println();        // 修改副对象中第一个元素的引用对象中的年龄、名称属性        vice.get(0).getPet().setAge(10);        vice.get(0).getPet().setName("小猫");        System.out.println("主对象: " + main);        System.out.println("副对象: " + vice);        System.out.println("在拷贝对象中,修改第一个元素的引用类型Pet后,是否在同一个堆内存当中: " + (main.get(0).getPet() == vice.get(0).getPet()));        System.out.println();        System.out.println("可以发现,它是对'主'对象的拷贝,它不会拷贝'主'对象深层次的可变对象,只做第一层的拷贝");    }}// 宠物对象class Pet {    private String name;    private int age;    public Pet(String name, int age) {        this.name = name;        this.age = age;    }// ...省略set、get方法    @Override    public String toString() {        return "Pet{" +                "name='" + name + '\'' +                ", age=" + age +                '}';    }}// 主人对象class Master {    private String gender;    private Pet pet;    public Master(String gender) {        this.gender = gender;    }    public Master() {    }// ...省略set、get方法    @Override    public String toString() {        return "Master{" +                "gender='" + gender + '\'' +                ", pet=" + pet +                '}';    }}
  • 输出结果

在这里插入图片描述

结论由此可知,org.springframework.beans.BeanUtils工具类中的copyProperties()方法无法实现深拷贝,只能实现浅拷贝

来源地址:https://blog.csdn.net/Wei_Naijia/article/details/128791555

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

Spring学习笔记(一)【BeanUtils.copyProperties方法】

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

下载Word文档

猜你喜欢

NumPy 学习笔记(一)

NumPy:  1、NumPy 是一个功能强大的第三方库(需要自己安装),主要用于对多维数组执行计算;     它提供了大量的库函数和操作,可以帮助程序员更轻松地进行数值计算  2、可以和另外两个第三方库 SciPy 和 Matplotli
2023-01-31

MySQL 学习笔记 (一)

1.InnoDB and Online DDLALTER TABLE tbl_name ADD PRIMARY KEY (column), ALGORITHM=INPLACE, LOCK=NONE;https://dev.mysql.com/doc/refma
2016-12-04

NumPy学习笔记(一)

# NumPy### 安装- 通过安装Anaconda安装NumPy,一个开源的Python发行版本,其包含了conda、Python等180多个科学包及其依赖项,包含了大量的科学计算相关的包,其中就包括NumPy- 通过pip安装,
2023-01-31

python dict()方法学习笔记

学习PYTHON 的dict()方法笔记。  dict() -> new empty dictionary |  dict(mapping) -> new dictionary initialized from a mapping obje
2023-01-31

第一周Python学习笔记

Python 基本语法:①  Python程序的格式:1.用代码高亮来标识函数丶语句等等 本身的代码高亮并没有实际的意义,只是用来辅助编程人员和阅读人员 更好的识别   2.程序以缩进来标识语句,缩进用来标识代码间的层次关系,缩进的长度也必
2023-01-30

Python第一周 学习笔记(3)

一、数值型1.数据类型分类:int:整数python3的int就是长整型,且没有大小限制,受限于内存区域的大小int(x) 返回一个整数float:浮点数有整数部分和小数部分组成。支持十进制和科学计数法表示。只有双精度型。float(x)
2023-01-31

Python学习笔记一(Python数据

Python数据类型主要包括数字,字符串,列表,元组和字典。字符串,列表,元组和字典都是序列,序列最主要两个特点是索引操作和切片操作,索引操作让我们从序列中抓取一个特定项目,切片操作让我们能够获取序列的一个切片,即一部分序列。1.数字 P
2023-01-31

编程热搜

  • Python 学习之路 - Python
    一、安装Python34Windows在Python官网(https://www.python.org/downloads/)下载安装包并安装。Python的默认安装路径是:C:\Python34配置环境变量:【右键计算机】--》【属性】-
    Python 学习之路 - Python
  • chatgpt的中文全称是什么
    chatgpt的中文全称是生成型预训练变换模型。ChatGPT是什么ChatGPT是美国人工智能研究实验室OpenAI开发的一种全新聊天机器人模型,它能够通过学习和理解人类的语言来进行对话,还能根据聊天的上下文进行互动,并协助人类完成一系列
    chatgpt的中文全称是什么
  • C/C++中extern函数使用详解
  • C/C++可变参数的使用
    可变参数的使用方法远远不止以下几种,不过在C,C++中使用可变参数时要小心,在使用printf()等函数时传入的参数个数一定不能比前面的格式化字符串中的’%’符号个数少,否则会产生访问越界,运气不好的话还会导致程序崩溃
    C/C++可变参数的使用
  • css样式文件该放在哪里
  • php中数组下标必须是连续的吗
  • Python 3 教程
    Python 3 教程 Python 的 3.0 版本,常被称为 Python 3000,或简称 Py3k。相对于 Python 的早期版本,这是一个较大的升级。为了不带入过多的累赘,Python 3.0 在设计的时候没有考虑向下兼容。 Python
    Python 3 教程
  • Python pip包管理
    一、前言    在Python中, 安装第三方模块是通过 setuptools 这个工具完成的。 Python有两个封装了 setuptools的包管理工具: easy_install  和  pip , 目前官方推荐使用 pip。    
    Python pip包管理
  • ubuntu如何重新编译内核
  • 改善Java代码之慎用java动态编译

目录