zoukankan      html  css  js  c++  java
  • Cloneable接口和Object的clone()方法

    为什么要克隆

    为什么要使用克隆,这其实反映的是一个很现实的问题,假如我们有一个对象:

    复制代码
    public class SimpleObject implements Cloneable
    {
        private String str;
        
        public SimpleObject()
        {
            System.out.println("Enter SimpleObject.constructor()");
        }
    
        public String getStr()
        {
            return str;
        }
    
        public void setStr(String str)
        {
            this.str = str;
        }
        
        public Object clone() throws CloneNotSupportedException
        {
            return super.clone();
        }
    }
    复制代码

    现在我写一段程序:

    复制代码
    public static void main(String[] args)
    {
        SimpleObject so0 = new SimpleObject();
        so0.setStr("111");
        System.out.println("so0.getStr():" + so0.getStr());
        SimpleObject so1 = so0;
        so1.setStr("222");
        System.out.println("so0.getStr():" + so0.getStr());
        System.out.println("so1.getStr():" + so1.getStr());
    }
    复制代码

    运行结果其实很明显:

    so0.getStr():111
    so0.getStr():222
    so1.getStr():222

    Java底层使用C/C++实现的,"="这个运算符,如果左右两边都是对象引用的话,在Java中表示的将等号右边的引用赋值给等号左边的引用,二者指向的还是同一块内存,所以任何一个引用对内存的操作都直接反映到另一个引用上。

    但是,现在我想拿这个so0的数据进行一些操作,不想改变原来so0中的内容,这时候就可以使用克隆了,它允许在堆中克隆出一块和原对象一样的对象,并将这个对象的地址赋予新的引用,这样,显然我对新引用的操作,不会影响到原对象。

    当然,理解克隆,最好还是对Java内存区域有比较好的理解。

    Cloneable接口和Object的clone()方法

    Java中实现了Cloneable接口的类有很多,像我们熟悉的ArrayList、Calendar、Date、HashMap、Hashtable、HashSet、LinkedList等等。

    还是那句话,对于不熟悉的接口、方法,第一反应一定是查询JDK API。

    1、Cloneable接口

    三句话总结:

    (1)此类实现了Cloneable接口,以指示Object的clone()方法可以合法地对该类实例进行按字段复制

    (2)如果在没有实现Cloneable接口的实例上调用Object的clone()方法,则会导致抛出CloneNotSupporteddException

    (3)按照惯例,实现此接口的类应该使用公共方法重写Object的clone()方法,Object的clone()方法是一个受保护的方法

    2、Object的clone()方法

    创建并返回此对象的一个副本。对于任何对象x,表达式:

    (1)x.clone() != x为true

    (2)x.clone().getClass() == x.getClass()为true

    (3)x.clone().equals(x)一般情况下为true,但这并不是必须要满足的要求

    克隆实例

    把上面例子的main函数修改一下:

    复制代码
    public static void main(String[] args) throws Exception
    {
        SimpleObject so0 = new SimpleObject();
        so0.setStr("111");
        SimpleObject so1 = (SimpleObject)so0.clone();
        
        System.out.println("so0 == so1?" + (so0 == so1));
        System.out.println("so0.getClass() == so1.getClass()?" + (so0.getClass() == so1.getClass()));
        System.out.println("so0.equals(so1)?" + (so0.equals(so1)));
            
        so1.setStr("222");
        System.out.println("so0.getStr():" + so0.getStr());
        System.out.println("so1.getStr():" + so1.getStr());
    }
    复制代码

    看一下运行结果:

    Enter SimpleObject.constructor()
    so0 == so1?false
    so0.getClass() == so1.getClass()?true
    so0.equals(so1)?false
    so0.getStr():111
    so1.getStr():222

    得到三个结论:

    1、克隆一个对象并不会调用对象的构造方法,因为"Enter SimpleObject.constructor()"语句只出现了一次

    2、符合JDK API的clone()方法三条规则

    3、so1对于SimpleObject对象str字段的修改再也不会影响到so0了

    浅克隆和深克隆

    浅克隆(shallow clone)和深克隆(deep clone)反映的是,当对象中还有对象的时候,那么:

    1、浅克隆,即很表层的克隆,如果我们要克隆对象,只克隆它自身以及它所包含的所有对象的引用地址

    2、深克隆,克隆除自身对象以外的所有对象,包括自身所包含的所有对象实例

    这两个概念应该很好理解,就不写代码了。多提一句,所有的基本数据类型,无论是浅克隆还是深克隆,都会进行原值克隆,毕竟它们都不是对象,不是存储在堆中的。

    那其实Object的clone()方法,提供的是一种浅克隆的机制,如果想要实现对对象的深克隆,在不引入第三方jar包的情况下,可以使用两种办法:

    1、先对对象进行序列化,紧接着马上反序列化出

    2、先调用super.clone()方法克隆出一个新对象来,然后在子类的clone()方法中手动给克隆出来的非基本数据类型(引用类型)赋值,比如ArrayList的clone()方法:

    复制代码
    public Object clone() {
    try {
        ArrayList<E> v = (ArrayList<E>) super.clone();
        v.elementData = Arrays.copyOf(elementData, size);
        v.modCount = 0;
        return v;
    } catch (CloneNotSupportedException e) {
        // this shouldn't happen, since we are Cloneable
        throw new InternalError();
    }
    }
    复制代码
  • 相关阅读:
    第一节,Django+Xadmin打造上线标准的在线教育平台—创建用户app,在models.py文件生成3张表,用户表、验证码表、轮播图表
    Tensorflow 错误:Unknown command line flag 'f'
    Python 多线程总结
    Git 强制拉取覆盖本地所有文件
    Hive常用函数 傻瓜学习笔记 附完整示例
    Linux 删除指定大小(范围)的文件
    Python 操作 HBase —— Trift Trift2 Happybase 安装使用
    梯度消失 梯度爆炸 梯度偏置 梯度饱和 梯度死亡 文献收藏
    Embedding 文献收藏
    深度学习在CTR预估中的应用 文献收藏
  • 原文地址:https://www.cnblogs.com/szlbm/p/5504649.html
Copyright © 2011-2022 走看看