【Java基础】2.对象拷贝

这篇具有很好参考价值的文章主要介绍了【Java基础】2.对象拷贝。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

深拷贝:

=创建一个新对象,然后将当前对象的非静态字段复制到该新对象。

==无论该字段是基本类型的还是引用类型,都复制独立的一份。当你修改其中一个对象的任何内容时,都不会影响另一个对象的内容。

浅拷贝:

=创建一个新对象,然后将当前对象的非静态字段复制到该新对象。

==基本数据类型复制的是值;
==引用数据类型复制的是对象的引用(不可变类型特殊)。(原引用对象发生改变时,复制的新对象的值也会发生改变。)
==注意:String类型、Integer等基本数据类型的包装类型,因为是不可变类型,所以即使进行的是浅拷贝,原始对象的改变并不会影响目标对象。

1)通过clone方法(浅拷贝)

Student s1 = new Student();
s1.setName("1");
s1.setAge(12);
s1.setSex("man");

Student s2 = (Student) s1.clone();

2)重新定义clone方法(深拷贝);区分final对象

class Student implements Cloneable{
	@Override
	protected Student clone() throws CloneNotSupportedException {
	    Student newStudent = (Student) super.clone();
	    newStudent.teacher = (Teacher) teacher.clone();
	    return newStudent;
	}
}

class Teacher implements Cloneable{
	@Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
}

$:要实现彻底的深拷贝,必须从被拷贝对象中所引用的对象属性层层往下实现Cloneable接口,并重写@Override clone方法,把该 对象引用的其他对象也clone一份。

3)序列化克隆(深拷贝)

序列化和反序列化:对象的寿命通常随着生成该对象的程序的终止而终止,有时候需要把在内存中的各种对象的状态(也就是实例变量,不是方法)保存下来,并且可以在需要时再将对象恢复。
将序列化对象写入文件之后,可以从文件中读取出来,并且对它进行反序列化,也就是说,对象的类型信息、对象的数据,还有对象中的数据类型可以用来在内存中新建对象。

=使用场景:
想把的内存中的对象状态保存到一个文件中或者数据库中时候;
想把对象通过网络进行传播的时候;

=原理:

要保存的对象实现Serializable接口,定义serialVersionUID;
通过ObjectOutputStream中的writeObect序列化一个对象,并发送到输出流进行转移复制;
通过ObjectInputStream中的readObject从流中取出下一个对象,并进行反序列化。

代码如下:
Person.class

/**
 * 对象类需要实现序列化接口Serializable
 */
public class Person implements Serializable {
    //对象属性和方法定义好后自动生成序列化ID
    private static final long serialVersionUID = -7814987656430454056L; 
    private String name;
    private int age;

    public Person(String name,int age){
        this.name = name;
        this.age = age;
    }

    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

CopyUtil.class

public class CopyUtil {

    /**
     * 通过ObjectOutputStream的writeObject方法将对象写出到某个路径下的文件
     *
     * @param path
     * @param person
     */
    public static void writeObject(String path, Person person) {
        File file = new File(path);
        FileOutputStream fos = null;
        try {
            fos = new FileOutputStream(file);
            ObjectOutputStream oos = null;
            try {
                System.out.println("person:" + person.toString());
                oos = new ObjectOutputStream(fos);
                oos.writeObject(person);            //写入对象,序列化
                oos.flush();
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                if (oos != null) {
                    try {
                        oos.close();
                    } catch (IOException e) {
                        System.out.println("OOS关闭失败:" + e.getMessage());
                    }
                }
            }
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }
    }


    /**
     * 通过ObjectInputStream的readObject方法读取某个路径下的文件
     * @param path
     */
    public static void readObject(String path) {
        File file = new File(path);
        FileInputStream fis = null;
        try {
            fis = new FileInputStream(file);
            ObjectInputStream ois = null;
            try {
                ois = new ObjectInputStream(fis);
                Person person = (Person) ois.readObject();
                System.out.println("person:" + person.toString());
            } catch (IOException e) {
                e.printStackTrace();
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            } finally {
                if (ois != null) {
                    try {
                        ois.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }
    }
}

Main.class

  public static void main(String[] args) {
        Person person = new Person("小王",18);
        String path = "copy/out.txt";
        System.out.println("开始写出文件到:");
        CopyUtil.writeObject(path,person);
        System.out.println("开始读取序列化后的文件:");
        CopyUtil.readObject(path);
    }

控制台输出:

开始写出文件到:
person:Person{name=‘小王’, age=18}
开始读取序列化后的文件:
person:Person{name=‘小王’, age=18}
Process finished with exit code 0

序列化文件保存的对象数据:

aced 0005 7372 002c 636f 6d2e 7374 7564
792e 6261 7369 632e e5ba 8fe5 8897 e58c
96e5 afb9 e8b1 a1e6 8bb7 e8b4 9d2e 5065
7273 6f6e 938b 9621 ce66 7ad8 0200 0249
0003 6167 654c 0004 6e61 6d65 7400 124c
6a61 7661 2f6c 616e 672f 5374 7269 6e67
3b78 7000 0000 1274 0006 e5b0 8fe7 8e8b

总结:

  1. 查看了文件序列化后保存的对象数据内容,可以得出通过序列化这种方式来实现对象拷贝或者存储,本质上就是用序列化的方式保存了对象的属性状态,并进行存储,后续再次读取出来的时候保证了一致性;
  2. 核心方法为ObjectOutputStream.writeObject()ObjectInputStream.readObject()
  3. 对于ObjectOutputStream如何去实现序列化输出的,可以详细参考这篇文章:

深入理解Java序列化机制:ObjectOutputStream源码简要分析

4)BeanUtils.copyProperties()函数(浅拷贝)

使用org.springframework.beans.BeanUtils包中的函数: BeanUtils.copyProperties(a, b); //a对象拷贝到b
#:避免使用org.apache.commons.beanutils.BeanUtils

5)MapStruct编译期在接口的实现类中进行了转换(深拷贝)

依赖:

<dependency>
    <groupId>org.mapstruct</groupId>
    <artifactId>mapstruct</artifactId>
    <version>1.3.1.Final</version>
</dependency>

由于在编译期生成代码,需要在maven-compiler-plugin插件中配置:

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-compiler-plugin</artifactId>
    <version>3.8.1</version>
    <configuration>
        <source>1.8</source> <!-- depending on your project -->
        <target>1.8</target> <!-- depending on your project -->
        <annotationProcessorPaths>
            <path>
                <groupId>org.mapstruct</groupId>
                <artifactId>mapstruct-processor</artifactId>
                <version>1.3.1.Final</version>
            </path>
            <!-- other annotation processors -->
        </annotationProcessorPaths>
    </configuration>
</plugin>

①定义mapper接口:

@Mapper
public interface UserMapper {

    UserMapper INSTANCE = Mappers.getMapper(UserMapper.class);

    @Mappings({
            @Mapping(source = "id", target = "id"),
            @Mapping(source = "createTime", target = "createTime")
    })
    UserVO dtoToVo(UserDTO userDTO);
}

②实现类:

public class UserMapperImpl implements UserMapper {
    public UserMapperImpl() {
    }

    public UserVO dtoToVo(UserDTO userDTO) {
        if (userDTO == null) {
            return null;
        } else {
            UserVO userVO = new UserVO();
            userVO.setIdd(userDTO.getId());
            userVO.setCreateTime(userDTO.getCreateTime());
            userVO.setUserName(userDTO.getUserName());
            return userVO;
        }
    }
}

③使用:文章来源地址https://www.toymoban.com/news/detail-612513.html

public static void main(String[] args) {
    UserDTO userDTO = new UserDTO();
    userDTO.setId(1);
    userDTO.setUserName("哈哈");
    userDTO.setCreateTime(new Date());
    UserVO userVO = UserMapper.INSTANCE.dtoToVo(userDTO);
    System.out.println(JSON.toJSONString(userVO));
}

到了这里,关于【Java基础】2.对象拷贝的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • web开发学习笔记(8.java web后端开发基础知识)

    1.使用spring开发的优势,spring发展到今天已经形成了一种开发生态圈,提供了若干个子项目,每个项目用于完成特定的功能。使用spring全家桶,可以做到很多事情,可以很方便的套用很多的组件。 2.pom构成 指定父工程 指定web构件 指定springboot打包控件 3.启动类的写法 4.contro

    2024年01月18日
    浏览(63)
  • Java 学习路线:基础知识、数据类型、条件语句、函数、循环、异常处理、数据结构、面向对象编程、包、文件和 API

    Java 是一种由 Sun Microsystems 于 1995 年首次发布的编程语言和计算平台。Java 是一种通用的、基于类的、面向对象的编程语言,旨在减少实现依赖性。它是一个应用程序开发的计算平台。Java 快速、安全、可靠,因此在笔记本电脑、数据中心、游戏机、科学超级计算机、手机等领

    2024年03月24日
    浏览(88)
  • 【Java基础】2.对象拷贝

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

    2024年02月15日
    浏览(34)
  • Pyhton基础知识:整理18 -> 基于面向对象的知识完成数据分析的案例开发

    数据准备:两份数据,一份是是字符串的形式,一份是json格式,之后对数据处理后,需要合并为一份的数据,进而进行图表的开发      

    2024年01月17日
    浏览(48)
  • Java基础知识篇——Java基本介绍

    Java 是 Sun Microsystems 于 1995 年首次发布的一种 编程语言 和计算平台。编程语言还是比较好理解的,什么是 计算平台 呢? 计算平台是电脑中运行应用程序(软件的环境),包括硬件环境和软件环境。一般系统平台包括一台电脑的硬件体系结构,操作系统、运行时库。 Java 是快

    2024年03月11日
    浏览(48)
  • 【Java基础】Java容器相关知识小结

    目录 0. 前言 1. Collection接口 1.1. List接口 1.1.1. ArrayList 1.1.2. LinkedList 1.1.3. Vector 1.1.4. Stack 1.2. Set接口 1.2.1. HashSet 1.2.2. LinkedHashSet 1.2.3. TreeSet 1.3. Queue接口 1.3.1. PriorityQueue 1.3.2. LinkedList 2. Map接口 2.1. HashMap 2.2. TreeMap 2.3. LinkedHashMap 3.常见用法——增/删/改/查/排序/容量 后记 参考文章

    2024年02月05日
    浏览(86)
  • java基础知识

    java的数据结构有哪些? 线性结构:数组、链表、哈希表;队列、栈 非线性结构有:堆、树(二叉树、B树、B+树、红黑树) 图 常用的集合类有List集合,Set集合,Map集合,其中List集合与Set集合继承了Collection接口, List 有序可重复的集合接口,继承自Collection接口,表示元素按照插入顺

    2024年02月06日
    浏览(52)
  • java基础知识梳理

    虽然已经在实际工作中与java打交道5年之多,但是一直没系统地对java这门语言进行梳理和总结,掌握的知识也比较零散。恰好利用这段时间重新认识下java,并对一些常见的语法和知识点做个总结与回顾,一方面为了加深印象,方便后面查阅,一方面为了学好java打下基础。拉

    2024年02月04日
    浏览(63)
  • Java入门基础知识

    JDK是Java工具开发包,包含了JVM(程序运行环境),核心类库(直接应用即可),开发工具(Javac,java,jdb,jhat…) JRE是Java运行环境,包含了JVM,核心类库,运行工具 JDK包含了JRE,JRE包含了jvm 全部小写(有特定含义的英文字符) class 表示一个类 整数类型 小数类型 字符串类型 :只用\\\"双引

    2024年02月09日
    浏览(69)
  • java基础知识二

    1.1、基本概念 类是具有相同属性和行为的一组对象的 集合 ,包含数据和操作,数据被称为 成员变量 ,操作被称为方法 对象是类的实例,即 对象 = 数据 + 行为 或者 对象 = 状态 + 操作 类抽象的、概念上的定义,对象是一个具体的、实际存在的个体,即一个实例 1.2、类的特

    2024年02月07日
    浏览(55)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包