Java:接口应用(Clonable 接口和深拷贝)

目录

  • 1.引例
  • 2.Object中clone方法的实现
  • 3.Cloneable接口讲解
  • 4.深拷贝和浅拷贝
    • 4.1浅拷贝
    • 4.2深拷贝

1.引例

Java 中内置了一些很有用的接口, Clonable 就是其中之一.
Object 类中存在一个 clone 方法, 调用这个方法可以创建一个对象的 “拷贝”. 但是要想合法调用 clone 方法。必须要先实现 Clonable 接口。 否则就会抛出异常.
( CloneNotSupportedException )
如下所示,当我们要克隆一个我们已经实例化的Student类该怎么去实现呢?

class Student{
    private int age;
    public Student(int age) {
        this.age = age;
    }
    @Override
    public String toString() {
        return "Student{" +
                "age=" + age +
                '}';
    }
}
public class Test {
    public static void main(String[] args) {
        Student student1=new Student(10);
    }
}

首先,我们要知道Java中所有的类都继承Object类
当我们找到Object类的原码时,我们会发现一个clone()方法
在这里插入图片描述
那我们可能会想:既然所有的类都继承Object类,那当我们要克隆student1,直接通过student1.clon去调用这个克隆方法来实现克隆操作,但是真正去实现的时候就会发现以下问题:我们找不到这个方法。
在这里插入图片描述

2.Object中clone方法的实现

在这里插入图片描述
为什么找不到Object类中的clone方法呢,通过原码我们能看到Object类中clone方法由protected修饰
protected:同包下可以访问,不同包只有子类能访问
所以我们进行第一步,方法的重写
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
重写后可以引用clone方法了,但是我们会发现还是报错,因为引用的clone方法是父类的。
当我们要将它传给子类我们就要进行第二步:强制转换
在这里插入图片描述
强制转换后还是报错,这样我们就需要进行第三步:(涉及异常知识,后面再进行补充)

public class Test {
    public static void main(String[] args) throws CloneNotSupportedException {
        Student student1=new Student(10);
        Student student2=(Student)student1.clone();
        System.out.println(student2.toString());
    }
}

在这里插入图片描述

这时解决完异常问题后,当我们真正进行运行时还是会报错,这样我们就要进行第四步:实现Cloneable接口
在这里插入图片描述
在这里插入图片描述
完成以上四步后就可以成功完成clone了。
完整代码

class Student implements Cloneable{
    private int age;
    public Student(int age) {
        this.age = age;
    }
    @Override
    public String toString() {
        return "Student{" +
                "age=" + age +
                '}';
    }
    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
}
public class Test {
    public static void main(String[] args) throws CloneNotSupportedException {
        Student student1=new Student(10);
        Student student2=(Student)student1.clone();
        System.out.println(student2.toString());
    }
}

输出结果
在这里插入图片描述

3.Cloneable接口讲解

通过原码可以发现Cloneable里面什么也没有,是一个空接口(也叫标记接口)。
在这里插入图片描述

4.深拷贝和浅拷贝

4.1浅拷贝

class Money{
    public double money=12.5;
}
class Student implements Cloneable{
    private int age;
    public Money m=new Money();
    public Student(int age) {
        this.age = age;
    }
    @Override
    public String toString() {
        return "Student{" +
                "age=" + age +
                '}';
    }
    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
}
public class Test {
    public static void main(String[] args) throws CloneNotSupportedException {
        Student student1=new Student(10);
        Student student2=(Student)student1.clone();
        System.out.println(student2.toString());
    }
}

我们在上面的代码中加入了Money类并且在Student类中实例化了一个Money。
这时我们再进行克隆如下图所示
在这里插入图片描述
当我们对student1进行可能时money并没有也克隆一份,这样就是浅拷贝。举例如下:
在这里插入图片描述
在这里插入图片描述
我们只是改变了student2的money,但是student1的money也跟着改变了。

4.2深拷贝

class Money implements Cloneable{
    public double money=12.5;
    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
}
class Student implements Cloneable{
    private int age;
    public Money m=new Money();
    public Student(int age) {
        this.age = age;
    }
    @Override
    public String toString() {
        return "Student{" +
                "age=" + age +
                '}';
    }
    @Override
    protected Object clone() throws CloneNotSupportedException {
        Student temp=(Student)super.clone();
        temp.m= (Money)this.m.clone();
        return temp;
    }
}
public class Test {
    public static void main(String[] args) throws CloneNotSupportedException {
        Student student1=new Student(10);
        Student student2=(Student)student1.clone();
        System.out.println(student1.m.money);
        System.out.println(student2.m.money);
        System.out.println("================");
        student2.m.money=100;
        System.out.println(student1.m.money);
        System.out.println(student2.m.money);
    }
}

我们使Money类也重写clone方法,并对Student类中的clone方法进行了改动,来实现深拷贝
在这里插入图片描述
举例如下
在这里插入图片描述
在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Qt | Qt 的重要文件简介(推荐)

一、项目文件(pro 文件)及其语法 1、项目文件(pro 文件)的作用是列举项目中的源文件, 2、pro 文件的语法形式为:“变量 操作符 值”,比如 QT += widgets,多个值之间使用空格分开。 3、pro 文件的注释:从“#”开始,直至本行结束。 4、pro 文件的操作符见下表 5、pro 文…

【美团笔试题汇总】2023-09-02-美团春秋招笔试题-三语言题解(CPP/Python/Java)

🍭 大家好这里是KK爱Coding ,一枚热爱算法的程序员 ✨ 本系列打算持续跟新美团近期的春秋招笔试题汇总~ 💻 ACM银牌🥈| 多次AK大厂笔试 | 编程一对一辅导 👏 感谢大家的订阅➕ 和 喜欢&#x1f…

使用 mitmproxy 抓包 grpc

昨天在本地执行 grpc 的 quick start(python版本的),我了解 grpc 内部使用的是 HTTP2,所以我就想着抓包来试试,下面就来记录一下这个过程中的探索。 注意:我的电脑上面安装了 Fiddler Classic,…

数据结构day2--双向链表

双向链表: 即可以从头遍历到尾部和从尾部遍历到头部的链表,每个结点包括两个链域:前驱指针域和后继指针域,所以比起单向链表,其可以在任意一个结点访问前后两个结点 关于双向链表的一个完整步骤为: 创建一个表头结构…

微软detours代码借鉴点备注

comeasy 借鉴点1 Loadlibray的时间选择 注入库wrotei.dll,为了获取istream的接口,需要loadlibrary,但是在dllmain中是不建议这样做的。因此,动态库在dllmain的时候直接挂载了comeasy.exe的入口 //获取入口 TrueEntryPoint (i…

【其他】灾害预警,科技助力:手机地震预警功能设置指导

22024年4月3日7时58分在台湾花莲县海域遭遇了一场7.3级的强烈地震,震源深度12公里,震中位于北纬23.81度,东经121.74度,距台湾岛约14公里。震中5公里范围内平均海拔约-3560米。这场突如其来的自然灾害给当地居民的生活带来了巨大的…

【MATLAB】GA_BP神经网络时序预测算法

有意向获取代码,请转文末观看代码获取方式~ 1 基本定义 GA_BP神经网络时序预测算法是一种结合了遗传算法(GA)和反向传播(BP)神经网络的时序预测方法。它利用了遗传算法的全局搜索和优化能力,以及BP神经网络的学习和逼近能力,可以更有效地预…

Qtxlsx第三方库的安装和使用

本文仅作为一个记录,安装QtXlsx方便操作excel,主要参考了这篇博文:https://blog.csdn.net/u014779536/article/details/111769792 1,下载安装Perl脚本Strawberry Perl for Windows,默认安装strawberry-perl-5.30.0.1-…

【Redis教程0x0F】Redis实战篇

Redis如何实现延迟队列? 延迟队列是指把当前要做的事情,往后推迟一段时间再做。延迟队列的常见使用场景有以下几种: 在淘宝、京东等购物平台上下单,超过一定时间未付款,订单会自动取消;打车的时候&#x…

ES6学习(五)-- Module 语法

文章目录 Module 语法1.1 痛点介绍(1) 异步加载(2) 私密(3) 重名(4) 依赖 1.2 解决方法(1) 解决异步加载问题(2) 解决私密问题(3) 重名解决方法(4) 解决依赖问题 1.3 模块化使用案例 Module 语法 之前js 出现的某些痛点: 在script 中引入的变量名不可以重复&#…

深入了解 Python 中标准排序算法 Timsort

🍉 CSDN 叶庭云:https://yetingyun.blog.csdn.net/ Timsort:一个非常快速的、时间复杂度为 O ( n l o g n ) O (n \ log\ n) O(n log n)、稳健(即不改变等值元素间的相对顺序)的排序算法,在处理真实世界数…

蓝桥杯单片机真题实践篇

这里就不完全写思路过程代码什么的,这一篇文章就写我在训练真题中遇到的过程。 (呜呜呜,时间不够辣,能做多少算多少吧....) 十三届省赛题 问题1:数码管的数字消影不明显 (参考:蓝…

ms-前端八股文

1、暂时性死区 是指在 JavaScript 中使用 let 或 const 声明变量时,变量在其声明之前不能被访问或使用的特性。 var可以变量提升(在 JavaScript 中,变量声明提升是指在执行代码之前,变量声明会被提升到作用域的顶部。&#xff0…

SSM 项目学习(Vue3+ElementPlus+Axios+SSM)

文章目录 1 项目介绍1.1 项目功能/界面 2 项目基础环境搭建2.1 创建项目2.2 项目全局配置 web.xml2.3 SpringMVC 配置2.4 配置 Spring 和 MyBatis , 并完成整合2.5 创建表,使用逆向工程生成 Bean、XxxMapper 和 XxxMapper.xml2.6 注意事项和细节说明 3 实现功能 01-…

【C++】二叉搜索数

目录 一、二叉搜索树的概念 二、二叉搜索树的模拟实现 1、定义节点 2、构造二叉树 3、析构二叉树 ​4、拷贝二叉树 5、二叉树赋值 6、插入节点 🌟【非递归方式】 🌟【递归方式】 7、打印节点 8、搜索节点 🌟【非递归方式】 &…

臻奶惠无人售货奶柜:定义新时代的健康生活方式

臻奶惠无人售货奶柜:定义新时代的健康生活方式 臻奶惠的无人售货奶柜,代表着科技与生活方式融合的一个新趋势,它不仅仅是一个简单的购买平台,更是一种全新的生活体验。在这个快节奏的时代,臻奶惠通过其无人售货奶柜&a…

第四百四十三回

文章目录 1. 概念介绍2. 思路与方法2.1 整体思路2.2 使用方法 3. 示例代码4. 内容总结 我们在上一章回中介绍了"自定义Action菜单"相关的内容,本章回中将介绍如何获取屏幕相关参数.闲话休提,让我们一起Talk Flutter吧。 1. 概念介绍 我们在本…

(一)小案例银行家应用程序-介绍

案例示例如下所示: 登录之后就会出现下面所示: 项目案例流程图如下 ● 首先我们建立四个账号对象,用于登录 const account1 {owner: ItShare,movements: [200, 450, -400, 3000, -650, -130, 70, 1300],interestRate: 1.2, // %pin: 11…

数学建模-最优包衣厚度终点判别法(主成分分析)

💞💞 前言 hello hello~ ,这里是viperrrrrrr~💖💖 ,欢迎大家点赞🥳🥳关注💥💥收藏🌹🌹🌹 💥个人主页&#xff…

线程安全问题与解决方法~

本文内容仅供对线程安全问题、锁的认识和使用等,进行一个介绍。适合小白的文章! 目录 一、线程安全问题 1.什么是线程安全问题 2.解释上述安全问题 3.线程安全的五大原因 二、使用锁解决线程安全问题 1.介绍锁 2.加锁操作 一、线程安全问题 在多线…