Java之Clonable接口和深浅拷贝

news/2024/7/7 19:19:25

Clonable接口

我们船舰了一个人的对象,想要克隆一个一模一样的对象,可以用到object类里面的克隆方法

object不是所有类的父类吗?那为什么用person1点不出这个方法呢?可以看一下源码

这是Object类里面的clone方法的声明,native说明这是本地方法,底层是由c/c++实现的。注意,它的访问权限是protected,所以再不同包中的子类只可以用super来引用,但super又不能静态方法中使用,所以我们只能再Person类里面重写一个方法,如下:

但还是报错,注意throws CloneNotSupportedException表示克隆不支持异常,语法规定,我们需要在main方法后面也加上这一句,同时,clone方法的返回值是Object类型,但在main方法中我们用了它的子类来接收,这是向下转型,必须要用括号强转,如下:

但还是报错,这就是 CloneNotSupportedException,即不支持克隆,那么这时,Clonable接口就起作用了,我们需要让那个被克隆的类去实现Clonable接口,如下:

空接口/标记接口

我们再看一下接口的源码:

发现里面没有任何抽象方法,这就是一个空接口或者叫标记接口,表示该类可以被拿去克隆

将上面的错误全部修正后,person1就可以被克隆了

深拷贝与浅拷贝

现在,我们再在person类里面加一个成员变量money,它是Money类的

class Money{

    public double m=29.9;
    
}
class Person implements Cloneable{
    public String name;
    public int age;
    public Money money=new Money();
    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
}
public class Test {
    public static void main(String[] args)throws CloneNotSupportedException  {
        Person person1=new Person("张三",20);
        Person person2=(Person)person1.clone();
        System.out.println("person1:"+person1.money.m);
        System.out.println("person1:"+person2.money.m);
        System.out.println("==========");
        person1.money.m=99.9;
        System.out.println("person1:"+person1.money.m);
        System.out.println("person1:"+person2.money.m);
        
        
    }
}

如上,那输出的结果是什么?

浅拷贝

按理说,即使person2是克隆出来的,但它也是一个独立的个体,应该不会受person1的影响,可却出现了上面的现象,实际上,在拷贝money时,由于money是个引用类型,它的值是所指对象的地址,在拷贝时,就将person1的money的值直接给到了person2的money,导致两个money都指向了同一个对象,而不是我们想看到的不是同一个对象而只是有一样的值罢了。

这种对于money的拷贝就是浅拷贝

深拷贝

那如何进行深拷贝?其实就是再给person2的money另外开辟一块空间,然后再将person1的money所指对象的值拷贝到person2的money所指对象。既然要克隆money,那么就要让money也支持克隆,如下

第二张图的第二行代码是刚刚的浅拷贝,在它的基础上再将money也拷贝一份,就能实现真正意义上的一式两份,也就是深拷贝。那么我们如何将二三行代码合在一起?先看一下重写的克隆方法:

这个方法是放在哪个类就克隆哪个类,由于在person类里面重写的clone方法仅支持person的克隆,所以我们可以修改这个克隆方法使他还可以将内部的money也克隆一份,而不仅仅是克隆其表面的值,如下:

可是,这个代码有很大的问题,当我们用this.clone时,就会出现死循环,一i那位这是自己调用了自己,所以应该修改为用Object类的clone方法,即用到super,如下:

这时修改1的值就不会影响2了

最终代码就是

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

    public double m=29.9;

}
class Person implements Cloneable{
    public String name;
    public int age;
    public Money money=new Money();
    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

    @Override
    protected Object clone() throws CloneNotSupportedException {
       Person tmp=(Person) super.clone();
       Money money=(Money) this.money.clone();
       tmp.money=money;
       return tmp;
    }
}
public class Test {
    public static void main(String[] args)throws CloneNotSupportedException  {
        Person person1=new Person("张三",20);
        Person person2=(Person)person1.clone();
        //person2.money= (Money) person1.money.clone();
        System.out.println("person1:"+person1.money.m);
        System.out.println("person2:"+person2.money.m);
        System.out.println("==========");
        person1.money.m=99.9;
        System.out.println("person1:"+person1.money.m);
        System.out.println("person2:"+person2.money.m);


http://lihuaxi.xjx100.cn/news/1898990.html

相关文章

云计算:FusionCompute 通过 FreeNAS 添加SAN存储

目录 一、实验 1.环境准备 2.FusionCompute添加CNA 3.在存储中创建LUN资源映射给CNA节点 3.添加存储资源关联CNA主机节点 4.扫描存储资源 5.将存储设备添加为数据存储 二、问题 1.FusionCompute中存储如何分类 2.存储资源与存储设备有何区别 3.FusionCompute支持哪些…

技术分享 | 常见接口协议解析

服务与服务之间传递数据包,往往会因为不同的应用场景,使用不同的通讯协议进行传递。比如网站的访问,常常会使用 HTTP 协议进行传递,文件传输使用 FTP,邮件传递使用 SMTP。上述的三种类型的协议都处于网络模型中的应用层…

C语言—每日选择题—Day50

一天一天的更新,也是达到50天了,精选的题有250道,博主累计做了不下500道选择题,最喜欢的题型就是指针和数组之间的计算呀,不知道关注我的小伙伴是不是一直在坚持呢?文末有投票,大家可以投票让博…

8.鸿蒙app java代码构建用户界面

鸿蒙app java代码构建用户界面 background_ability_main.xml <?xml version"1.0" encoding"UTF-8" ?> <shape xmlns:ohos"http://schemas.huawei.com/res/ohos"ohos:shape"rectangle"><solidohos:color"#8F71…

20.HTTP 协议

HTTP 的特性 • HTTP 协议构建于 TCP/IP 协议之上&#xff0c;是一个应用层协议&#xff0c;默认端口号是 80 • HTTP 是无连接无状态的 HTTP 报文 请求报文 HTTP 协议是以 ASCII 码传输&#xff0c;建立在 TCP/IP 协议之上的应用层规范。规范把 HTTP 请求分为三个部分&…

实验记录:可能造成深度学习模型训练过程中准确率振荡的原因

可能造成模型训练过程中准确率振荡的原因&#xff1a; 数据集因素&#xff1a; 1.数据集中含有噪声或者样本分布不平衡&#xff0c;这会导致模型学习到一些错误的规律&#xff0c;从而引起训练准确率的震荡。 2.训练数据量过小。如果训练数据集过小&#xff0c;会导致样本不足…

计算机服务器中了360后缀勒索病毒怎么处理,勒索病毒解密数据恢复

网络技术的不断发展与应用&#xff0c;越来越多的企业开始走向数字化办公模式&#xff0c;极大地方便了企业的生产运营。但随之而来的网络安全威胁也在不断增加&#xff0c;在本月&#xff0c;云天数据恢复中心陆续接到很多企业的求助&#xff0c;企业的计算机服务器遭到了360后…

CEF 窗口全屏

有时候需要全屏播放视频,这时候就需要将CEF所在的窗口全屏,这样,就可以全屏显示CEF网页了 。 相关文章: 从 chromium源码中 去除CEF对requestFullscreen()限制 目录 一、窗口全屏 1、全屏前保存原先的位置