栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > .Net

Java随笔-clone

.Net 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

Java随笔-clone

为什么要使用clone

为什么要使用clone,直接new一个对象不就好了吗,实际使用中,直接new一个对象也不好,解决不了"新数据"会影响原始数据的问题。
这里简单创建了一个测试对象WhyClone。

public class WhyClone {
    private String name;

    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
}

然后创建两个WhyClone 对象,并且使用一个对另一个赋值,赋值之后修改被赋值的内容。

    
    static void whyClone(){
        WhyClone wc1 = new WhyClone();
        wc1.setName("wc1");
        WhyClone wc2 = new WhyClone();
        wc2 = wc1;
        // 输出wc1与wc2的地址
        System.out.println(wc1);
        System.out.println(wc2);
        // 输出wc1与wc2的内容
        System.out.println(wc1.getName());
        System.out.println(wc2.getName());
        // 修改wc2的内容
        wc2.setName("wc2");
        // 输出wc1与wc2的地址
        System.out.println(wc1);
        System.out.println(wc2);
        // 输出wc1与wc2的内容
        System.out.println(wc1.getName());
        System.out.println(wc2.getName());
    }

编译结果:

clone.WhyClone@7a07c5b4
clone.WhyClone@7a07c5b4
wc1
wc1
clone.WhyClone@7a07c5b4
clone.WhyClone@7a07c5b4
wc2
wc2

查看结果发现:wc2被wc1赋值后,wc1和wc2指向同一块地址clone.WhyClone@7a07c5b4,且内容相同,且给wc2赋值字符串”wc2“后,wc1的内容也变成”wc2“。通常开发者需要改变wc2的值且不影响wc1,这就是为什么要使用clone的原因。

clone分为浅拷贝和深拷贝。 浅拷贝

拷贝时,拷贝对象需要实现Cloneable接口,并重写clone() 。

public class ShallowClone implements Cloneable{
    private String name;
    private Inner inner;
    
    public Inner getInner() {
        return inner;
    }
    public void setInner(Inner inner) {
        this.inner = inner;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    @Override
    public Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
    public static class Inner{
        public Inner(String tag) {
            this.tag = tag;
        }
        public String  tag;
    }
}

测试代码:

    
    static void shallowClone() throws CloneNotSupportedException {
        ShallowClone sc1 = new ShallowClone();
        sc1.setInner(new ShallowClone.Inner("inner"));
        sc1.setName("sc1");
        ShallowClone sc2 = (ShallowClone) sc1.clone();
        // 输出sc1与sc2的地址
        System.out.println(sc1);
        System.out.println(sc2);
        System.out.println(sc1.getInner());
        System.out.println(sc2.getInner());
        // 输出sc1与sc2的内容
        System.out.println(sc1.getName());
        System.out.println(sc2.getName());
        System.out.println(sc1.getInner().tag);
        System.out.println(sc2.getInner().tag);
        // 是否是浅拷贝
        System.out.println(sc1.getName() == sc2.getName());
        // 修改sc2的内容
        sc2.setName("sc2");
        sc2.getInner().tag = "outer";
        // 输出sc1与sc2的地址
        System.out.println(sc1);
        System.out.println(sc2);
        System.out.println(sc1.getInner());
        System.out.println(sc2.getInner());
        // 输出sc1与sc2的内容
        System.out.println(sc1.getName());
        System.out.println(sc2.getName());
        System.out.println(sc1.getInner().tag);
        System.out.println(sc2.getInner().tag);
    }

编译结果:


比较编译结果发现:直接修改name属性,sc1和sc2并不互相影响,但是两者的Inner指向的是同一个,修改sc2对象Inner的tag属性后,sc1也被修改了,说明ShallowClone.Inner用的同一个,想要一刀两断又没有彻底了断,属于藕断丝连的情况,也就是clone不彻底,称之为浅拷贝。

深拷贝

深拷贝顾名思义就是除了是同一类型的外,所有属性都没有联系,新对象是一块完全独立的内存,两者之间没有任何影响。

public class DeepCloneOuter implements Cloneable{
    public DeepCloneInner deepCloneInner;
    @Override
    public Object clone() throws CloneNotSupportedException {
        DeepCloneOuter deepCloneOuter = (DeepCloneOuter) super.clone();
        deepCloneOuter.deepCloneInner = (DeepCloneInner) deepCloneInner.clone();
        return deepCloneOuter;
    }
}
public class DeepCloneInner implements Cloneable, Serializable {
    private String name;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

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

测试代码:

    
    static void deepClone() {
        System.out.println("*****************************");
        DeepCloneOuter deepCloneOuter = new DeepCloneOuter();
        deepCloneOuter.deepCloneInner = new DeepCloneInner();
        deepCloneOuter.deepCloneInner.setName("source");

        try {
            DeepCloneOuter deepCloneOuter2 = (DeepCloneOuter) deepCloneOuter.clone();
            System.out.println(deepCloneOuter);
            System.out.println(deepCloneOuter2);
            System.out.println(deepCloneOuter.deepCloneInner.getName());
            System.out.println(deepCloneOuter2.deepCloneInner.getName());
            System.out.println(deepCloneOuter.deepCloneInner.getName() == deepCloneOuter2.deepCloneInner.getName());
            System.out.println(deepCloneOuter.deepCloneInner == deepCloneOuter2.deepCloneInner);
            // 修改内容
            deepCloneOuter2.deepCloneInner.setName("clone");
            System.out.println(deepCloneOuter);
            System.out.println(deepCloneOuter2);
            System.out.println(deepCloneOuter.deepCloneInner.getName());
            System.out.println(deepCloneOuter2.deepCloneInner.getName());
            System.out.println(deepCloneOuter.deepCloneInner.getName() == deepCloneOuter2.deepCloneInner.getName());
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }
    }

编译结果:

clone.DeepCloneOuter@68de145
clone.DeepCloneOuter@27fa135a
source
source
true
false
clone.DeepCloneOuter@68de145
clone.DeepCloneOuter@27fa135a
source
clone
false
false


编译结果说明深拷贝拷中的对象除了长得像,初此之外没有任何联系。当拷贝对象比较复杂的时候,该拷贝方法需要单独拷贝很多东西,所以不常用,利用序列化拷贝对象较为常用。

序列化深拷贝

序列化深拷贝是通过序列化对象,之后反序列化,利用字节流写入被拷贝对象并读取后得到新对象,相当于用户参照被拷贝对象手动开辟了一块新内存供新对象使用。
需要拷贝的对象只要实现Serializable即可。

public class SerializationClone implements Serializable {
    private String name;
    private Inner inner;
    public Inner getInner() {
        return inner;
    }
    public void setInner(Inner inner) {
        this.inner = inner;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public static class Inner implements Serializable{
        private String tag;

        public String getTag() {
            return tag;
        }
        public void setTag(String tag) {
            this.tag = tag;
        }
    }
}```

拷贝工具:

```java
public class CloneUtil {

    public static  T clone(T objection){
        T cloneObjection = null;
        try {
            // 创建写入字节流
            ByteArrayOutputStream out = new ByteArrayOutputStream();
            ObjectOutputStream obs = new ObjectOutputStream(out);
            // 写入被拷贝对象
            obs.writeObject(objection);
            // 关闭字节流输入流
            obs.close();

            // 创建字节输入流,分配内存,写入原始对象,生成新对象
            ByteArrayInputStream ios = new ByteArrayInputStream(out.toByteArray());
            ObjectInputStream ois = new ObjectInputStream(ios);
            // 返回生成的新对象
            cloneObjection = (T) ois.readObject();
            // 关闭对象输入流
            ois.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
        // 返回新对象
        return cloneObjection;
    }
}

测试代码:

    
    static void serializationClone(){
        SerializationClone serializationClone = new SerializationClone();
        serializationClone.setName("serializationClone");
        SerializationClone.Inner inner = new SerializationClone.Inner();
        inner.setTag("serializationCloneTag");
        serializationClone.setInner(inner);
        // 输出原数据
        System.out.println("**************原数据**********");
        System.out.println(serializationClone);
        System.out.println(serializationClone.getInner());
        System.out.println(serializationClone.getName());
        System.out.println(serializationClone.getInner().getTag());

        // 拷贝后
        SerializationClone serializationClone1 = CloneUtil.clone(serializationClone);
        System.out.println("**************拷贝后**********");
        System.out.println(serializationClone1);
        System.out.println(serializationClone1.getInner());
        System.out.println(serializationClone1.getName());
        System.out.println(serializationClone1.getInner().getTag());

        // 修改
        serializationClone1.setName("serializationClone1");
        serializationClone1.getInner().setTag("serializationClone1Tag1");
        // 原数据
        System.out.println("**************修改后原数据**********");
        System.out.println(serializationClone);
        System.out.println(serializationClone.getInner());
        System.out.println(serializationClone.getName());
        System.out.println(serializationClone.getInner().getTag());
        // 拷贝后修改的数据
        System.out.println("**************修改后拷贝数据**********");
        System.out.println(serializationClone1);
        System.out.println(serializationClone1.getInner());
        System.out.println(serializationClone1.getName());
        System.out.println(serializationClone1.getInner().getTag());
    }

编译结果:

**************原数据**********
clone.SerializationClone@26a1ab54
clone.SerializationClone$Inner@3d646c37
serializationClone
serializationCloneTag
**************拷贝后**********
clone.SerializationClone@156643d4
clone.SerializationClone$Inner@123a439b
serializationClone
serializationCloneTag
**************修改后原数据**********
clone.SerializationClone@26a1ab54
clone.SerializationClone$Inner@3d646c37
serializationClone
serializationCloneTag
**************修改后拷贝数据**********
clone.SerializationClone@156643d4
clone.SerializationClone$Inner@123a439b
serializationClone1
serializationClone1Tag1

比较拷贝前后的对象发现两者地址都不一样,包括内部对象的地址,修改任何属性也不会相互影响。

深拷贝建议使用序列化深拷贝
转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/985414.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号