java中clone方法的理解(深拷贝、浅拷贝)

来源:互联网 发布:相册排版制作软件 编辑:程序博客网 时间:2024/06/03 11:03

前言:

java中的clone一直是一个老生常谈的问题,另外关于克隆网上也有很多的写过这方面的问题。我在这里记录一下我遇到的问题和使用clone的方法。

知识点一:什么是浅拷贝?

    我们这里说的浅拷贝是指我们拷贝出来的对象内部的引用类型变量和原来对象内部引用类型变量是同一引用(指向同一对象)。    但是我们拷贝出来的对象和新对象不是同一对象。    简单来说,新(拷贝产生)、旧(元对象)对象不同,但是内部如果有引用类型的变量,新、旧对象引用的都是同一引用。

知识点二:什么是深拷贝?

深拷贝:全部拷贝原对象的内容,包括内存的引用类型也进行拷贝

知识点三、java拷贝(clone)的前提:

1.首先我们需要知道Object类中一个clone()的方法,并且是protected关键字修饰的本地方法(使用native关键字修饰),我们完成克隆需要重写该方法。注意:按照惯例重写的时候一个要将protected修饰符修改为public,这是JDK所推荐的做法,但是我测试了一下,复写的时候不修改为public也是能够完成拷贝的。但是还是推荐写成public2.我们重写的clone方法一个要实现Cloneable接口。虽然这个接口并没有什么方法,但是必须实现该标志接口。如果不实现将会在运行期间抛出:CloneNotSupportedException异常3.Object中本地clone()方法,默认是浅拷贝

知识点四:浅拷贝案例:

拷贝类:

package cn.cupcat.java8;/** * Created by xy on 2017/12/25. */public class Person implements Cloneable{    private String name;    private int age;    private int[] ints;    public int[] getInts() {        return ints;    }    public Person(String name, int age, int[] ints) {        this.name = name;        this.age = age;        this.ints = ints;    }    public void setInts(int[] ints) {        this.ints = ints;    }    public String getName() {        return name;    }    public void setName(String name) {        this.name = name;    }    public int getAge() {        return age;    }    public void setAge(int age) {        this.age = age;    }    public Person(String name, int age) {        this.name = name;        this.age = age;    }    /**     *  默认实现     * */    @Override    public Object clone() throws CloneNotSupportedException {        return  super.clone();    }}

测试类:

package cn.cupcat.java8;import org.junit.Test;/** * Created by xy on 2017/12/25. */public class CloneTest  {    @Test    public void test() throws CloneNotSupportedException {        int[] ints = {1,2,3};        String name = "zhangxiangyang";        int age = 23;        Person person = new Person("zhangxiangyang",age,ints);        System.out.print("一:克隆前:  age = "+ age + "... name = "+ name + " 数组:");        for (int i : ints){            System.out.print(i + " ");        }        System.out.println();        //拷贝        Person clonePerson = (Person) person.clone();        int clonePersonAge = clonePerson.getAge();        String clonePersonName = clonePerson.getName();        int[] ints1 = clonePerson.getInts();        System.out.print("二:克隆后: age = "+ clonePersonAge + "... name = "+ clonePersonName + " 数组: ");        for (int i : ints1){            System.out.print(i + " ");        }        System.out.println();        //修改:        ints1[0] = 50;        //修饰        clonePerson.setName("666666666");        age = person.getAge();        name = person.getName();        System.out.println();        System.out.print("三:修改后原对象: age = "+ age + "... name = "+ name + "数组 ");        for (int i : ints){            System.out.print(i + " ");        }        System.out.println();        System.out.println("四:person == clonePerson ? "+ (person == clonePerson ));    }}

结果为:

一:克隆前:  age = 23... name = zhangxiangyang 数组:1 2 3 二:克隆后: age = 23... name = zhangxiangyang 数组: 1 2 3 三:修改后原对象: age = 23... name = zhangxiangyang数组 50 2 3 四:person == clonePerson ? false

总结:

1.通过四输出  person == clonePerson ? false 可以看出,克隆以后的对象已经和以前不是同一对象了。因为其引用是不同的。2.通过分析一、二可以看出我们的拷贝成功执行了,并且拷贝的数据也都正确3.通过分析三,我们修改了拷贝后对象的name、ints        ints1[0] = 50;        //修饰        clonePerson.setName("666666666");  发现原对象中的ints也跟着修改了,因此可以证明拷贝后的对象和原对象的ints数组指向了同一引用。  而我们发现同时也修改了拷贝对象name属性,为什么那么原对象中的name属性没有发生改变呢?  而且String类型也是引用类型呀? 别急,下面我会画图示意。4. 通过以上总结,我们得出结论:clone()方法的默认实现是浅拷贝       

下面通过画图示意:

拷贝成功后:
这里写图片描述

修改拷贝对象过后:
这里写图片描述

ps:如果看不清楚图片,可以在标签窗口打开

知识点五:深拷贝案例:

该类只和浅拷贝在clone方法的实现上有区别,其他地方相同:

package cn.cupcat.java8;/** * Created by xy on 2017/12/25. */public class Person implements Cloneable{    private String name;    private int age;    private int[] ints;    public int[] getInts() {        return ints;    }    public Person(String name, int age, int[] ints) {        this.name = name;        this.age = age;        this.ints = ints;    }    public void setInts(int[] ints) {        this.ints = ints;    }    public String getName() {        return name;    }    public void setName(String name) {        this.name = name;    }    public int getAge() {        return age;    }    public void setAge(int age) {        this.age = age;    }    public Person(String name, int age) {        this.name = name;        this.age = age;    }    /**     *  深拷贝     * */    @Override    public Object clone() throws CloneNotSupportedException {        Person person = new Person(name,age);        int[] ints = new int[this.ints.length];        System.arraycopy(this.ints,0,ints,0,ints.length);        person.setInts(ints);        return  person;    }}

该测试类和前拷贝测试类相同:

package cn.cupcat.java8;import org.junit.Test;/** * Created by xy on 2017/12/25. */public class CloneTest  {    @Test    public void test() throws CloneNotSupportedException {        int[] ints = {1,2,3};        String name = "zhangxiangyang";        int age = 23;        Person person = new Person("zhangxiangyang",age,ints);        System.out.print("克隆前:  age = "+ age + "... name = "+ name + " 数组:");        for (int i : ints){            System.out.print(i + " ");        }        System.out.println();        //拷贝        Person clonePerson = (Person) person.clone();        int clonePersonAge = clonePerson.getAge();        String clonePersonName = clonePerson.getName();        int[] ints1 = clonePerson.getInts();        System.out.print("克隆后: age = "+ clonePersonAge + "... name = "+ clonePersonName + " 数组: ");        for (int i : ints1){            System.out.print(i + " ");        }        System.out.println();        //修改:        ints1[0] = 50;        //修饰可控后的对象        clonePerson.setName("666666666");        age = person.getAge();        name = person.getName();        System.out.println();        System.out.print("修改后原对象: age = "+ age + "... name = "+ name + "数组 ");        for (int i : ints){            System.out.print(i + " ");        }        System.out.println();        System.out.println("person == clonePerson ? "+ (person == clonePerson ));    }}

结果为:

一:克隆前:  age = 23... name = zhangxiangyang 数组:1 2 3 二:克隆后: age = 23... name = zhangxiangyang 数组: 1 2 3 三:修改后原对象: age = 23... name = zhangxiangyang数组 1 2 3 四:person == clonePerson ? false

总结:

1.通过四可以看出完成了拷贝,并且克隆对象和原对象不是同一对象(没有同一引用)2.通过一、二可以看出完成了拷贝并且数据正确3.通过三,我们修改克隆以后的对象,打印原对象发现没有影响到原对象的数据,也就是说完成的深拷贝  下面使用图解说明一下

画图说明:

拷贝完成后:
这里写图片描述

修改拷贝后对象后:

这里写图片描述

知识点六:总结

拷贝也算是我们经常使用的一个方法,但是如果是不明白其中原理的程序员可能还是会入坑的。下面总结几条使用建议: 1.一定要实现Cloneable接口 2.复写clone()方法,注意:默认是浅拷贝,这里需要将引用类型进行深拷贝处理 3.特殊:String类虽然是引用类型,但是是final类,同时也有字符串常量池的存在,不必进行处理
阅读全文
'); })();
0 0
原创粉丝点击
热门IT博客
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 螺蛳粉有螺蛳吗 螺蛳青鱼 螺蛳粉里面有螺蛳吗 螺蛳剪尾机 螺蛳粉没有螺蛳 小螺蛳 酱爆螺蛳 螺蛳怎么吃 螺蛳怎么做 螺蛳粉怎么没有螺蛳 辣炒螺蛳 螺蛳粉没螺蛳 香辣螺蛳 螺蛳粉红油 吃螺蛳 螺蛳鸭脚 螺蛳拼音 螺蛳结顶 煮螺蛳 螺蛳精 螺蛳王 螺蛳虾 海螺蛳 螺蛳鱼 螺蛳粉的危害 孕妇吃螺蛳粉 螺蛳粉怎么读 正宗柳州螺蛳粉 螺蛳粉怎么煮 螺蛳粉哪个牌子好吃 柳州螺蛳粉哪个牌子好吃 螺蛳粉汤底做法及配方 怀孕可以吃螺蛳粉吗 螺蛳肉怎么做好吃 螺蛳的营养价值 怀孕可以吃螺蛳粉 螺蛳粉为什么这么好吃 螺蛳粉的热量 螺蛳粉怎么吃 柳州螺蛳粉图片 怀孕能吃螺蛳粉吗