Clone使用

news2024/11/25 7:11:22

实现克隆接口:clone方法是默认是Object的方法

1)这个接口是一个标记性的接口(空接口),他们内部都没有方法和属性,实现这个接口表示这个对象都可以进行克隆,我们调用Object对象的Object.clone()方法,如果没有实现Cloneable的类对象调用clone()就会抛出CloneNotSupportedException异常

2)我们想要一个类具备拷贝实例的功能,除了要实现Cloneable接口,还必须要重写Object类的clone()方法

3)我们可以看到Object类的clone()方法是被protected修饰的,我们需要在重写的clone()方法通过super关键字调用Object的clone()方法,

4)Cloneable接口发挥的是标记功能,自定义类型需要用户自己去标记哪些类是可以被clone的,这个标记就是去实现Cloneable接口,试下了该接口的类就表示该类创建的对象可以被克隆

想要克隆自定义类型,就要实现克隆接口public interface Cloneable(){};空接口也叫作标记接口

1.浅拷贝:我们在拷贝一个对象的时候,对对象的基本数据类型的成员变量进行拷贝,但是对引用类型的成员变量只进行引用的传递,并没有创建一个新的对象,当对引用类型的修改会影响到要拷贝的对象,简而言之,浅拷贝只是复制所拷贝的地址,而不复制他的所引用的对象

package com.example.demo;
import lombok.Data;
@Data
class Student implements Cloneable{
    public String username;
    public String password;
    public Student(String username, String password) {
        this.username = username;
        this.password = password;
    }

    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
}
public class HelloWorld{
    public static void main(String[] args) throws CloneNotSupportedException {
        Student student1=new Student("李佳伟","12503487");
        Student student2= (Student) student1.clone();
        System.out.println(student1==student2);
//false,两个引用分别指向的对象的地址值不相同
    }
}
false
Student{username='李佳伟', password='12503487'}
Student{username='李佳伟', password='12503487'}

 

上面画的图就是克隆出来了一个新的对象和新的引用,但是由于这个对象的组成是一个基本数据类型,所以只对基本数据类型复制了一份

class Money{
    public double m=100.5;
        }
class Student implements Cloneable
{
    String name;
//实现这个接口要重写克隆方法
Money money=new Money();
    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
}

public class Tomact {
    public static void main(String[] args) throws CloneNotSupportedException {
        Student student1=new Student();
        Student student2= (Student) student1.clone();
        System.out.println(student1.money.m);
        System.out.println(student2.money.m);
        student2.money.m=199;
        System.out.println(student1.money.m);
        System.out.println(student2.money.m);
//都变成了199
    }
}

1)此时我们单纯的修改student1的username此时是不会修改student2的username的

2) 我们观察下面的代码,我们将Money类的实例引用作为了Student类的一个字段,new 一个Student类型的对象,将这个student1对象拷贝到student2对象,这里面的拷贝就是浅拷贝了,只是将student1的对象的money的引用进行拷贝了一份,此时student1和student2指向的两个不同对象的money引用指向的是同一个对象

package com.example.demo;
import lombok.Data;
@Data
class Student implements Cloneable{
    public String username;
    public String password;
    public Student(String username, String password) {
        this.username = username;
        this.password = password;
    }

    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
}
public class HelloWorld{
    public static void main(String[] args) throws CloneNotSupportedException {
        Student student1=new Student("李佳伟","12503487");
        Student student2= (Student) student1.clone();
        System.out.println(student1==student2);//false
    }
}

由此看出,只是拷贝了money对象的地址,他们仍然指向的是同一个对象,此时原来的对象和新被克隆出来的对象的成员变量money指向地址的都是 0x100

下面我们来实现一个真正意义上的深拷贝:

深拷贝:

我们在拷贝对象的时候,除了对基本的数据类型的成员变量进行拷贝的时候,对引用类型的成员变量进行拷贝的时候,创建一个新的对象来进行保存引用类型的成员变量,简单来说深拷贝不光把地址新创建了一份,还会把要进行复制的对象里面的引用所指向的对象也拷贝了一份

class Money implements Cloneable{
    public double m=100.5;

    @Override
    protected Object clone() throws CloneNotSupportedException {
        return  super.clone();

    }
}
class Student implements Cloneable
{
    String name;
    //实现这个接口要重写克隆方法
    Money money=new Money();
    @Override
    protected Object clone() throws CloneNotSupportedException {

          //return super.clone();正常情况下,Person的克隆是在这里面执行
         //Student s=(Student) super.clone();
         //return s;
        //1克隆Person
        Student s= (Student) super.clone();
        //2克隆当前的Money对象
        s.money= (Money) this.money.clone();
        return s;


        // 由于下面要进行Money的克隆
    }
}

public class Tomact {
    public static void main(String[] args) throws CloneNotSupportedException {
        Student student1=new Student();
        Student student2= (Student) student1.clone();
        System.out.println(student1.money.m);
        System.out.println(student2.money.m);
        student2.money.m=199;
        System.out.println(student1.money.m);
        System.out.println(student2.money.m);
        //这里面只是克隆了一个person,我们要想实现深拷贝
        //就要把Student对象中的money这个对象也克隆一份
    }
}

Java中的clone方法是一个浅拷贝,引用类型仍然在传递引用,我们可以通过继续调用clone方法,对该对象的引用类型变量在实现一次clone的方法来实现深拷贝

1)让我们的两个类都实现cloneable接口

2)在我们的Student类里面不光克隆Student对象里面的属性,还进行克隆Student类中的引用类型所指向的对象也进行克隆一份

class Money implements Cloneable{
    public int money;

    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
}
class Student implements Cloneable{
    public String username;
    public String password;
    public Student(String username, String password) {
        this.username = username;
        this.password = password;
    }
    Money money=new Money();
    @Override
    protected Object clone() throws CloneNotSupportedException {
       Student student=(Student)super.clone();
       student.money=(Money)money.clone();
       return student;
    }
    @Override
    public String toString() {
        return "Student{" +
                "username='" + username + '\'' +
                ", password='" + password + '\'' +
                '}';
    }
}
public class HelloWorld{
    public static void main(String[] args) throws CloneNotSupportedException {
        Student student1=new Student("李佳伟","12503487");
        Student student2= (Student) student1.clone();
        student1.money.money=999;
        System.out.println(student1.money.money);//999
        System.out.println(student2.money.money);//0
    }
}

我们拷贝简单类型是深拷贝,拷贝引用类型是浅拷贝,我们要想实现深拷贝,就要拷贝一下这个对象,只是拷贝地址值,是不能实现真正意义上的深拷贝的

1)咱们的数组的四种拷贝方法都是浅拷贝,因为我们大部分情况下是拷贝地址的,而现在是拷贝数据

2)深拷贝:如果我们拷贝完成之后,我们通过一个引用去访问去修改拷贝完成之后的值,是不会修改原来的值

3)浅拷贝:相反拷贝通过引用来进行修改,原来的值发生变化,就叫做浅拷贝

如果问数组的拷贝是什么拷贝?先问问到底是再拷贝什么???

static关键字修饰的成员是属于类的,而abstract一般是用来修饰普通方法目的是为了让子类继承后重写该方法,而static修饰的方法是不存在继承重写的

创建对象的方式:

  1. new关键字
  2. 反射
  3. Clone方法
  4. 反序列化使用ObjectMapper

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

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

相关文章

【云原生】k8s声明式资源管理

内容预知 1.资源配置清单的管理 1.1 查看资源配置清单 1.2 修改资源配置清单并应用 离线修改 在线修改 1.3 删除资源配置清单 2.自主编写资源清单 2.1 初步认识资源清单中svc的重要配置项 2.2 手动编写 svc资源配置 3.手动生成模板,再编写资源清单 &#x…

解决虚拟机IP地址无法获取和网络无法连接

首先看一下电脑的end33分配成功没有 ifconfig或者使用ip addr查询都可以 ip addr 目录 1.首先看看你的网络连接模式是不是NAT 2.去主机电脑服务查看这四个服务是否开启 3.查看虚拟机子网ip是否分配了 4.修改我们的网卡配置文件,使用下面命令进入文件 5.重启网…

jemeter 压测并生成报告

文章目录前言一、压测步骤1.1 创建jvm文件1.2 压测生成测试文件及html压测结果二、结果分析前言 jmeter:是Apche公司使用Java平台开发的一款测试工具。 一、压测步骤 1.1 创建jvm文件 添加测试计划 (当打开jmeter默认有一个测试计划)添加…

高并发下解决AtomicLong性能瓶颈的方案——LongAdder

一、 LongAdder简介 LongAdder类是JDK1.8新增的一个原子性操作类。上一节说到,AtomicLong通过CAS提供了非阻塞的原子性操作,相比用阻塞算法的synchronized来说性能已经得到了很大提升。在高并发下大量线程会同时竞争更新同一个原子变量,但由…

Qt 模型视图编程之重置模型数据

背景 Qt 模型视图编程中模型定义了标准接口对数据进行访问,可根据需求继承对应的抽象模型类来实现自定义的数据模型。一个基本的数据模型至少要实现以下虚函数: ①.rowCount:行数,返回要显示多少行; ②&…

软件工程---习题六

4. 图6.18给出的程序流程图代表一个非结构化的程序,问:   (1)为什么说它是非结构化的?   答:通常所说的结构化程序,是按照狭义的结构程序的定义衡量,符合定义规定的程序,每个代码…

【操作系统】模式切换篇

CPU的模式 什么是CPU的模式?这和CPU的发展过程有关,最开始CPU是8位的,后来发展到16位,然后是32位,现在是64位,多少多少位指的是寄存器的位宽。CPU能使用的寄存器宽度以及CPU使用的指令等就构成了CPU的模式…

传统ERP管理项目有哪些问题?项目ERP系统哪个好?

8Manage FAS 是专为基于项目的公司设计的企业资源规划系统(ERP系统)。基于项目的公司包括建筑、工程和施工操作 (AEC)、产品要订购制造 (ETO) 和各种其他类型的专业服务公司 (PSO)。 对任何公司来说,无论在什么行业,项目对其业务…

Linux 调试之 TRACE_EVENT

文章目录前言一、TRACE_EVENT简介二、TRACE_EVENT() 结构2.1 TRACE_EVENT简介2.2 trace_sched_switch示例三、The header file参考资料前言 在Linux的整个历史中,人们一直希望在内核中添加静态跟踪点,即记录内核中特定位置的数据以供以后检索的函数。与…

[附源码]Nodejs计算机毕业设计基于大数据的超市进销存预警系统Express(程序+LW)

该项目含有源码、文档、程序、数据库、配套开发软件、软件安装教程。欢迎交流 项目运行 环境配置: Node.js Vscode Mysql5.7 HBuilderXNavicat11VueExpress。 项目技术: Express框架 Node.js Vue 等等组成,B/S模式 Vscode管理前后端分…

开源大数据比对平台(dataCompare)新版本发布

开源大数据比对平台设计与实践—dataCompare 前文介绍了开源大数据比对平台设计和实践,最近将整体业务流程进行了完善和开发。 一、目前当前版本实现了如下功能: (1)低代码简单配置完成数据比对核心功能 (2)数据量级比对、数据一致性比对 二、系统功…

sentinel限流,熔断等具体流程分析

基于sentinel 1.8.6 从sentinel-dashboard来看,sentinel主要提供了流控,熔断,热点,系统规则,授权规则等。 针对http请求的数据监控以及规则限制的适配,可以参考sentinel-spring-webmvc-adapter以及sentin…

CBAM(Convolutional Block Attention Module)卷积注意力模块用法及代码实现

CBAM卷积注意力模块用法及代码实现CBAMChannel Attention模块(CAM)Spatial Attention模块(SAM)代码实现CBAM CBAM( Convolutional Block Attention Module )是一种轻量级注意力模块的提出于2018年。CBAM包…

185-200-spark-核心编程-Streaming

185-spark-核心编程-Streaming: 数据处理延迟的长短分为:实时数据处理(毫秒级别),离线数据处理(小时,天) 数据处理的方式分为:流式数据处理(streaming&…

ORACLE19c数据库随LINUX操作系统自动启动实现方式

1.建立目录 # su - oracle $ mkdir /home/oracle/scripts 2.建立启动脚本: $ cd /home/oracle/scripts $ vim startdb.sh #!/bin/bash export ORACLE_BASE/u01/app/oracle export ORACLE_HOME$ ORACLE_BASE/product/19.16.0/db_1 export ORACLE_SIDemrep export PAT…

【电脑使用】利用diskpart删除电脑的EFI分区

文章目录前言问题描述问题解决扩展:测量磁盘读写速度1 win10自带工具2 第三方工具前言 在Windows的磁盘管理中,往往会发现自己电脑的磁盘中莫名多了一些分区,有一些是系统分区(一般不删),还有一些是还原分区…

m索引OFDM调制解调系统的性能仿真分析

目录 1.算法描述 2.仿真效果预览 3.MATLAB核心程序 4.完整MATLAB 1.算法描述 随着无线通信技术的不断发展,人们对下一代移动通信系统提出了越来越高的要求。在这样的时代背景下,具有低峰均比,强频偏对抗能力和高能量效率的索引调制OFDM系统(Orthogonal Frequency Division …

【跟学C++】C++STL三大主要组件——容器/迭代器/算法(Study19)

文章目录1、前言2、简介2.1、STL是什么?2.2、STL能干什么?2.3、STL组成3、容器3.1、顺序容器3.2、排序容器(关联式容器)3.3、哈希容器3.4、容器适配器3、迭代器3.1、迭代器介绍3.2、迭代器定义方式3.3、迭代器类别3.4、辅助函数4、算法5、总结 【说明】…

【MATLAB教程案例60】使用matlab实现基于GRU网络的数据分类预测功能与仿真分析

欢迎订阅《FPGA学习入门100例教程》、《MATLAB学习入门100例教程》 目录 1.软件版本 2.GRU网络理论概述

【云原生进阶之容器】第一章Docker核心技术1.5.4节——cgroups使用

4 CGroups使用 4.1 挂载cgroup树 开始使用cgroup前需要先挂载cgroup树,下面先看看如何挂载一颗cgroup树,然后再查看其根目录下生成的文件。 #准备需要的目录 #准备需要的目录 dev@ubuntu:~$ mkdir cgroup && cd cgroup dev@ubuntu:~/cgroup$ mkdir demo#由于name=…