java浅度克隆_简单讲解java对象的浅度克隆与深度克隆

2023-10-10 18:59

本文主要是介绍java浅度克隆_简单讲解java对象的浅度克隆与深度克隆,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

在日常的开发中,我们经常会遇到需要克隆一个对象,对克隆的对象操作之后不影响原有对象以及与之关联的对象。

Java的Object类提供了clone方法,用来进行克隆对象,不过JDK提供的clone()方法只是浅度克隆,要想深度克隆需要自己来实现,那么什么是浅度克隆和深度克隆呢?

浅度克隆

JDK提供的克隆是浅度克隆,它只将对象中的基础数据类型的成员变量克隆到新对象中,对象中的引用类型只是克隆了一个引用,克隆后的引用类型还是指向原对象,如下图所示

59174221ef5ae0535380734bc82fdfdd.png

代码示例如下:

public class Teacher {

private String name;

private int age;

public Teacher(String name,int age){

this.name = name;

this.age = age;

}

public String getName() {

return name;

}

public void setName(String name) {

this.name = name;

}

public int getAge() {

return age;

}

public void setAge(int age) {

this.age = age;

}

}

public class User implements Cloneable{

private String name;

private int age;

private Teacher teacher;

public User(String name,int age){

this.name = name;

this.age = age;

}

public String getName() {

return name;

}

public void setName(String name) {

this.name = name;

}

public int getAge() {

return age;

}

public void setAge(int age) {

this.age = age;

}

public Teacher getTeacher() {

return teacher;

}

public void setTeacher(Teacher teacher) {

this.teacher = teacher;

}

@Override

protected User clone() throws CloneNotSupportedException {

User user = null;

try {

user = (User) super.clone();

} catch (CloneNotSupportedException e){

e.printStackTrace();

}

return user;

}

}

public class TestClone {

public static void main(String[] args) throws CloneNotSupportedException {

User user = new User("Tom",13);

user.setTeacher(new Teacher("Jack",40));

User userClone = user.clone();

userClone.getTeacher().setName("Jerry");

userClone.setName("Tom1");

userClone.setAge(20);

System.out.println(user.getName() + "|" + user.getAge() + "|" + user.getTeacher().getName());

System.out.println(userClone.getName() + "|" + userClone.getAge() + "|" + userClone.getTeacher().getName());

}

}

运行之后的输出结果为:

Tom|13|Jerry

Tom1|20|Jerry

从输出结果可以看出,克隆对象修改name和age不会影响原对象,但对引用类型Teacher做修改,就会影响原对象。

深度克隆

深度克隆就是把整个对象完全克隆一份,包括对象中的引用类型,如图所示

fc9303d2d5e3c9a47d95d56b9dc4eba1.png

JDK没有提供尝试克隆的方法,只能我们自己来实现,把User类的clone()方法自己实现一下就可以实现简单的尝试克隆了。其实很简单,例如:

@Override

protected User clone() throws CloneNotSupportedException {

User user = null;

try {

user = (User) super.clone();

//克隆的时候new一个Teacher对象,就可以实现深度克隆

Teacher te = new Teacher(this.teacher.getName(),this.teacher.getAge());

user.setTeacher(te);

} catch (CloneNotSupportedException e){

e.printStackTrace();

}

return user;

}

这样就可以实现User对象的深度克隆了,是不是很简单?

你以为这样就学会了深度克隆,那就真的太天真了,这里我只列举了一个最简单的对象

实际在开发过程中遇到的对象远远比这个要复杂的多,可能包含多层对象的嵌套,如果都自己去实现的话,那就太麻烦了,而且容易出现BUG

一种比较常用的实现方式是利用Java的序列化和反序列化

对象序列化必须实现Serializable接口:

import java.io.Serializable;

public class Teacher implements Serializable {

private String name;

private int age;

public Teacher(String name,int age){

this.name = name;

this.age = age;

}

public String getName() {

return name;

}

public void setName(String name) {

this.name = name;

}

public int getAge() {

return age;

}

public void setAge(int age) {

this.age = age;

}

}

import java.io.*;

public class TestClone {

public static void main(String[] args) throws IOException, ClassNotFoundException {

User user = new User("Tom",13);

user.setTeacher(new Teacher("Jack",40));

//序列化对象

ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();

ObjectOutputStream objectOutputStream = new ObjectOutputStream(byteArrayOutputStream);

objectOutputStream.writeObject(user);

//反序列化对象

ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(byteArrayOutputStream.toByteArray());

ObjectInputStream objectInputStream = new ObjectInputStream(byteArrayInputStream);

User cloneUser = (User) objectInputStream.readObject();

cloneUser.setName("Tom_clone");

cloneUser.setAge(20);

cloneUser.getTeacher().setName("Jack_clone");

System.out.println(user.getName() + "|" + user.getAge() + "|" + user.getTeacher().getName());

System.out.println(cloneUser.getName() + "|" + cloneUser.getAge() + "|" + cloneUser.getTeacher().getName());

}

}

Tom|13|Jack

Tom_clone|20|Jack_clone

可以看到已经完成了深度复杂,对引用类型的修改不会影响到原对象,这种方式的好处是不管对象嵌套多少层,对象进行序列化和反序列化之后,都会产生一个全新的对象

注意:static 和 transient 类型的变量不会被序列化,所以这两种类型的深度克隆不能使用序列化的方式。

这篇关于java浅度克隆_简单讲解java对象的浅度克隆与深度克隆的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/182435

相关文章

Spring Bean初始化及@PostConstruc执行顺序示例详解

《SpringBean初始化及@PostConstruc执行顺序示例详解》本文给大家介绍SpringBean初始化及@PostConstruc执行顺序,本文通过实例代码给大家介绍的非常详细,对大家的... 目录1. Bean初始化执行顺序2. 成员变量初始化顺序2.1 普通Java类(非Spring环境)(

Spring Boot 中的默认异常处理机制及执行流程

《SpringBoot中的默认异常处理机制及执行流程》SpringBoot内置BasicErrorController,自动处理异常并生成HTML/JSON响应,支持自定义错误路径、配置及扩展,如... 目录Spring Boot 异常处理机制详解默认错误页面功能自动异常转换机制错误属性配置选项默认错误处理

java如何实现高并发场景下三级缓存的数据一致性

《java如何实现高并发场景下三级缓存的数据一致性》这篇文章主要为大家详细介绍了java如何实现高并发场景下三级缓存的数据一致性,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 下面代码是一个使用Java和Redisson实现的三级缓存服务,主要功能包括:1.缓存结构:本地缓存:使

Java Spring的依赖注入理解及@Autowired用法示例详解

《JavaSpring的依赖注入理解及@Autowired用法示例详解》文章介绍了Spring依赖注入(DI)的概念、三种实现方式(构造器、Setter、字段注入),区分了@Autowired(注入... 目录一、什么是依赖注入(DI)?1. 定义2. 举个例子二、依赖注入的几种方式1. 构造器注入(Con

SpringBoot 异常处理/自定义格式校验的问题实例详解

《SpringBoot异常处理/自定义格式校验的问题实例详解》文章探讨SpringBoot中自定义注解校验问题,区分参数级与类级约束触发的异常类型,建议通过@RestControllerAdvice... 目录1. 问题简要描述2. 异常触发1) 参数级别约束2) 类级别约束3. 异常处理1) 字段级别约束

如何在Java Spring实现异步执行(详细篇)

《如何在JavaSpring实现异步执行(详细篇)》Spring框架通过@Async、Executor等实现异步执行,提升系统性能与响应速度,支持自定义线程池管理并发,本文给大家介绍如何在Sprin... 目录前言1. 使用 @Async 实现异步执行1.1 启用异步执行支持1.2 创建异步方法1.3 调用

java内存泄漏排查过程及解决

《java内存泄漏排查过程及解决》公司某服务内存持续增长,疑似内存泄漏,未触发OOM,排查方法包括检查JVM配置、分析GC执行状态、导出堆内存快照并用IDEAProfiler工具定位大对象及代码... 目录内存泄漏内存问题排查1.查看JVM内存配置2.分析gc是否正常执行3.导出 dump 各种工具分析4.

Spring Boot配置和使用两个数据源的实现步骤

《SpringBoot配置和使用两个数据源的实现步骤》本文详解SpringBoot配置双数据源方法,包含配置文件设置、Bean创建、事务管理器配置及@Qualifier注解使用,强调主数据源标记、代... 目录Spring Boot配置和使用两个数据源技术背景实现步骤1. 配置数据源信息2. 创建数据源Be

Spring Boot 3.x 中 WebClient 示例详解析

《SpringBoot3.x中WebClient示例详解析》SpringBoot3.x中WebClient是响应式HTTP客户端,替代RestTemplate,支持异步非阻塞请求,涵盖GET... 目录Spring Boot 3.x 中 WebClient 全面详解及示例1. WebClient 简介2.

Java中使用 @Builder 注解的简单示例

《Java中使用@Builder注解的简单示例》@Builder简化构建但存在复杂性,需配合其他注解,导致可变性、抽象类型处理难题,链式编程非最佳实践,适合长期对象,避免与@Data混用,改用@G... 目录一、案例二、不足之处大多数同学使用 @Builder 无非就是为了链式编程,然而 @Builder