【剧前爆米花--爪哇岛寻宝】Cloneable接口和深浅拷贝

news2024/11/18 12:23:51

作者:困了电视剧

专栏:《JavaSE语法与底层详解》

文章分布:这是一篇关于接口的文章,在本篇文章中我会分享Cloneable接口的用法和机制,同时从底层分析深拷贝和浅拷贝的区别。

 

Cloneable接口

Cloneable这类接口可以说是最能体现接口思想的一类接口了,cloneable是“可克隆的”意思,在源码中我们可以清晰地看到这个接口本身是没有任何内容的,在这里他是一个空接口,或者又被叫做标记接口,当我们想要使用clone()方法时,如果实例化该对象的类没有实现这个接口,那将无法使用clone()方法。

这个接口就像一个属性,在未实现它之前,这个类是不可克隆的,但当实现了这个接口后,它将转变为一个可以克隆的类。

clone方法的使用

clone()方法是Object类中的一个方法。

由源码中的写法我们可以看到,clone()方法的返回值是一个Object类,clone()方法被native修饰,说明它是由c/c++实现的方法,由protected可知,在不同的包中,他只能在子类中被使用。此时我想调用这个方法应该怎么做?

 

本图中我的Student类实现了Cloneable接口,但是当我在main方法中使用clone()方法时,却报错了,这是为什么?

这个原因很简单,因为Object是包含在Java.lang包中的,我们在我们自己定义的包中进行使用时,就属于不同包的使用,受于protected限制符,我们无法在其他类中进行使用,此时我们可以进行重写,将该方法移到当前包中就可以进行使用了,代码如下:

public class Javabit_Code {
    //这里需要声明一个编译型异常,否则会报错,我会在后面的文章中说明这个
    public static void main(String[] args) throws CloneNotSupportedException{
        Student student1=new Student();
        Student student2=(Student) student1.clone();

    }
}

class Student implements Cloneable{
    String name;
    int age;
    double soccer;

    public Student(String name, int age, double soccer) {
        this.name = name;
        this.age = age;
        this.soccer = soccer;
    }

    public Student(){}

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

由于该方法返回值是Object类型的,所以在接收的时候需要进行向下转型,否则会报错。 

浅拷贝

在完成上述拷贝的准备工作后,我们现在进行拷贝相关的操作,下段代码中我重写了toString方法,为了是我的代码的变换更直观和方便。

public class Javabit_Code {
    //这里需要声明一个编译型异常,否则会报错,我会在后面的文章中说明这个
    public static void main(String[] args) throws CloneNotSupportedException{
        Student student1=new Student("11",11,98);
        Student student2=(Student) student1.clone();
        System.out.println(student1);
        System.out.println(student2);
    }
}

class Student implements Cloneable{
    String name;
    int age;
    double soccer;

    public Student(String name, int age, double soccer) {
        this.name = name;
        this.age = age;
        this.soccer = soccer;
    }

    public Student(){}

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

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

执行结果为:

 由此可以看出我们完成了拷贝,student1和student2都是一样的内容,但此时突然有一个新的变化,我现在有一个新的Money类,每个学生类中都有一个Money类实例化的对象,然后每一个学生的money值都是固定的30,现在我将student1的nianl改为22,money值改为40,看看运行后会发生什么?

public class Javabit_Code {
    //这里需要声明一个编译型异常,否则会报错,我会在后面的文章中说明这个
    public static void main(String[] args) throws CloneNotSupportedException{
        Student student1=new Student("11",11,98);
        Student student2=(Student) student1.clone();
        System.out.println(student1);
        System.out.println(student2);
        System.out.println("=======================");
        student1.stuMoney.money=40;
        student1.age=22;
        System.out.println(student1);
        System.out.println(student2);
    }
}

class Student implements Cloneable{
    String name;
    int age;
    double soccer;
    Money stuMoney=new Money();

    public Student(String name, int age, double soccer) {
        this.name = name;
        this.age = age;
        this.soccer = soccer;
    }

    public Student(){}

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

    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", soccer=" + soccer +
                ", money=" + stuMoney +
                '}';
    }
}

class Money{
    double money=30;

    @Override
    public String toString() {
        return "Money{" +
                "money=" + money +
                '}';
    }
}

这是代码,其运行结果如图:

我们可以看到一个神奇的现象,我改了student1的年龄,student2的年龄并不会改变,但当我改了student1的money值时,student2 的也相应的发生了改变,这是什么原因?

我们从代码运行的底层分析一下:

clone()方法在运作时就是在堆区创建一个和被克隆的对象一模一样的对象,这两个对象由于是两个不同的对象,所以他们的地址并不相同,但其中的所有内容均一样,包括引用类型。

这时候问题就来了,既然我引用类型也一样,那我引用类型指向的不就是同一个地址吗?对,没错,这就是浅拷贝,即他虽然将一个对象的内容信息拷贝到另一个新的对象中了,但是对象当中的引用类型所指向的地址也原封不动的进行了拷贝,这就导致当我修改其中一个对象中引用类型变量的值时,用这种方法进行拷贝的所有对象的相应的值都会发生改变,这并不是我们一直想要的,那要如何进行改变呢? 

深拷贝

进行改变,即将浅拷贝转换成深拷贝,即当我进行拷贝的时候,我其中的引用类型也要指向一个全新的对象,那我不妨将clone()的方法再走一次,即我让本例中的Money类也实现Cloneable接口,然后在进行拷贝的时候同时拷贝一下money。

public class Javabit_Code {
    //这里需要声明一个编译型异常,否则会报错,我会在后面的文章中说明这个
    public static void main(String[] args) throws CloneNotSupportedException{
        Student student1=new Student("11",11,98);
        Student student2=(Student) student1.clone();
        System.out.println(student1);
        System.out.println(student2);
        System.out.println("=======================");
        student1.stuMoney.money=40;
        student1.age=22;
        System.out.println(student1);
        System.out.println(student2);
    }
}

class Student implements Cloneable{
    String name;
    int age;
    double soccer;
    Money stuMoney=new Money();

    public Student(String name, int age, double soccer) {
        this.name = name;
        this.age = age;
        this.soccer = soccer;
    }

    public Student(){}

    @Override
    protected Object clone() throws CloneNotSupportedException {
        Student student=(Student) super.clone();
        student.stuMoney=(Money) this.stuMoney.clone();
        return student;
    }

    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", soccer=" + soccer +
                ", money=" + stuMoney +
                '}';
    }
}

class Money implements Cloneable{
    double money=30;

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

    @Override
    public String toString() {
        return "Money{" +
                "money=" + money +
                '}';
    }
}

此时我们在进行一次运行:

student1的money发生改变,student2的money不会受到影响,此时就完成了深拷贝。

以上就是本篇博客的全部内容,如有疏漏欢迎指正!

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

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

相关文章

ZigBee硬件平台小记(CC2530)

文章目录1.CC2530射频模块特征2.CC2530射频模块主要技术指标3.调试器输出接口特点输出引脚排列1.CC2530射频模块特征 基于CC2530F256单芯片ZigBee SOC(System On Chip),集成8051内核模块尺寸:36mm x 26mmSMA底座,外接…

代码随想录训练营第56天|LeetCode 647. 回文子串、516.最长回文子序列

参考 代码随想录 题目一:LeetCode 647. 回文子串 如果用暴力求解,两层for循环加一层判断,两个遍历指针i和j构成一个区间,每次判断这个区间内的字符串是否为回文串,这样的求法时间复杂度为O(n^3)。这里使用动态规划可…

Jetpack Compose中的手势操作

点击事件 监听点击事件非常简单,使用 clickable 和 combinedClickable 修饰符即可满足需求: OptIn(ExperimentalFoundationApi::class) Composable fun ClickableExample() {Column{Box(Modifier.clickable { println("clickable") }.size(3…

异常检测原理及其在计算机视觉中的应用

点击上方“小白学视觉”,选择加"星标"或“置顶”重磅干货,第一时间送达这篇文章涵盖了三件事,首先什么是视觉角度的异常检测?用于异常检测的技术有哪些?它在哪里使用?异常检测是什么?…

微服务架构下的配置治理模式

微服务被滥用是不争的事实。被滥用的同时,很少人留意到它所带来的配置治理的问题。本文我们介绍两种常见的治理模式。基于common的配置治理模式当微服务数量多时,开发人员倾向于创建这样的配置文件:common-redis.jsoncommon-mysql.jsoncommon…

〖产品思维训练白宝书 - 产品思维认知篇③〗- 产品思维 VS 技术思维

大家好,我是 哈士奇 ,一位工作了十年的"技术混子", 致力于为开发者赋能的UP主, 目前正在运营着 TFS_CLUB社区。 💬 人生格言:优于别人,并不高贵,真正的高贵应该是优于过去的自己。💬 &#x1f4e…

【Numpy基础知识】Broadcasting广播

Numpy广播 来源:Numpy官网:https://numpy.org/doc/stable/user/basics.html 广播描述了 NumPy 在算术运算期间如何处理具有不同形状的数组。根据某些约束,较小的数组将“广播”到较大的阵列,以便它们具有兼容的形状。 导包 impo…

【Python机器学习】条件随机场模型CRF及在中文分词中实战(附源码和数据集)

需要源码请点赞关注收藏后评论区留言私信~~~ 基本思想 假如有另一个标注序列(代词 动词 名词 动词 动词),如何来评价哪个序列更合理呢? 条件随机场的做法是给两个序列“打分”,得分高的序列被认为是更合理的。既然要…

移动设备软件开发-Shape详解

Spape详解 1.自定义背景shape 1.1gradient 1.简介 定义渐变色,可以定义两色渐变和三色渐变,及渐变样式,它的属性有下面几个2.属性 angle,只对线性渐变是有效的放射性渐变必须指定放射性的半径,gradientRadiouscentetX和…

STM32的ST-link调试下载,各种调试接口硬件介绍

调试原理 STM32F-10X使用M3内核,该内核支持复杂的同i傲视操作,硬件调试模块允许在取指令(指令单步运行)或访问数据(数据断电时)使得内核停止。在内核停止时,内核状态都可被查询,完成…

JS基于编码方式实现加密解密文本

JS基于编码方式实现加密解密文本 严格来讲这是一种简单的编码方式:加密,将明文【注】转成编码。解密则是编码转码为明文本。 【注:明文是指没有加密的文字(或者字符串),一般人都能看懂。】 下面源码用到 这个fromCharCode() 方…

年底了,感谢大家2022年的支持,虚竹哥送10本JAVA好书

❤️作者主页:小虚竹 ❤️作者简介:大家好,我是小虚竹。Java领域优质创作者🏆,CSDN博客专家🏆,华为云享专家🏆,掘金年度人气作者🏆,阿里云专家博主&#x1f3…

碧兴物联IPO过会:拟募资4亿 预计年净利降幅超10%

雷递网 雷建平 12月21日碧兴物联科技(深圳)股份有限公司(简称:“碧兴物联”)日前IPO过会,准备在科创板上市。碧兴物联计划募资4.13亿元。其中,1.92亿元用于智慧生态环境大数据服务项目&#xff…

【MySQL】JDBC编程重点知识汇总

文章目录1. JDBC (API):2. JDBC代码编写:2.1 创建数据源对象:2.2 建立连接:2.3 构造SQL语句:2.4 执行SQL:2.5 释放资源:1. JDBC (API): 前面学过很多的SQL, 实际开发中大多数的SQL都不是手敲的, 都是通过程序来执行的. 各种的数据库都会提供API方便编程语言来控制; API (Appli…

【JavaEE】网络初识

初识网络协议 OSI七层和TCP/IP五层(四层) 应用层 应用程序 代码实现 传输层 端到端传输 (如玩家对玩家) 操作系统内核实现 网络层 点到点传输 操作系统内核实现 数据链路层 相邻节点之间的传输 (如集散点…

ChatGPT能接入微信了

前两天还看到不少人讨论,要是ChatGPT接入微信是啥感觉? 这不,想你所想,项目已经来了~ 来看效果,ChatGPT就出现在普通的微信对话框里,有问必答: 甚至还能拉入群聊,大家共用&#xf…

Adobe Premiere Pro 2020 系统兼容性报告:不支持的视频驱动程序

Adobe Premiere Pro 2020 系统兼容性报告:不支持的视频驱动程序 1. 问题 打开Adobe Premiere Pro 2020,看见系统兼容性报告:不支持的视频驱动程序。如下图: 点击修复,进入安装 Intel 图形驱动程序教程页面&#xff0…

DQL查询数据

文章目录DQL指定查询字段where条件子句联表查询分页和排序子查询DQL (Data Query Language:数据查询语言) 所有的查询操作都要用到它 select简单的查询,复杂的查询都要用到它数据库最核心的语言,最重要的语言使用频率…

python写个网页,使用flask显示时间登陆注册

用python写个网页。显示当前时间 可以使用 Python 的 datetime 模块来获取当前时间,然后使用 Python 的 Flask 框架来创建网页。 首先,需要安装 Flask: pip install flask 然后,可以使用以下代码创建一个 Flask 应用程序&#…

【Numpy基础知识】字节交换

字节交换 来源:Numpy官网:https://numpy.org/doc/stable/user/basics.html 文章目录字节交换导包【1】字节排序和ndarrays 简介【2】更改字节顺序导包 import numpy as np【1】字节排序和ndarrays 简介 ndarray 是一个对象,它为内存中的数据…