zoukankan      html  css  js  c++  java
  • 高质量编码--使用序列化实现对象的拷贝

    回顾

    回顾下对象拷贝的知识,为什么要拷贝对象呢,因为new对象往往是消耗资源的,使用对象拷贝的方式可以节省创建对象时的资源消耗,尤其对于大对象而言

    我们可以看下简单实现,下面这个类实现了Cloneable接口

    public class Person implements Cloneable{
            private String name;
            private Person parent;
    
            Person(String name){
                this.name = name;
            }
    
            Person(String name,Person parent){
                this.name = name;
                this.parent = parent;
            }
    
            @Override
            protected Object clone() throws CloneNotSupportedException {
                return super.clone();
            }
    
            // get,set方法省略...
    }
    

    类有了,下面这个方法会输出什么呢?

    public class Main {
    
        public static void main(String[] args) throws CloneNotSupportedException {
            Person father = new Person("老爹");
            Person xiaoming = new Person("小明", father);
            Person xiaogang = xiaoming.clone();
            xiaogang.name = "小刚";
            xiaoming.parent.name = "干爹";
            System.out.printf("%s的父亲-%s
    ",xiaoming.name,xiaoming.parent.name);
            System.out.printf("%s的父亲-%s
    ",xiaogang.name,xiaogang.parent.name);
        }
    

    Look

    我们现在假设个场景,小明和小刚是兄弟,他们俩的老爹欠了隔壁王大爷5块钱,木钱还咋办,老王说你让一个儿子认我做干爹,这事算结了,老爹没办法啊,只好同意了,于是小明认了老王做干爹,小刚看见了也去认老王当干爹去了,得,两个儿子全没了,老爹要气死

    这里就涉及到了浅拷贝的知识

    浅拷贝

    调用clone方法只会复制对象的基本类型和String,而对象则是复制引用,即小明和小刚的引用都是指向同一个父亲。
    有没有办法给小刚复制一个父亲,这样小明修改父亲属性就不会影响到小刚了。

    重写clone方法

    其实是有办法的,代码如下,给小刚重新new一个父亲就行。

    protected Person clone() throws CloneNotSupportedException {
        Person person = super.clone();
        person.setPerson(new Person(person.getName));
        return person;
    }
    

    序列化

    我们考虑这样一个问题,每次对象复制都要重写clone对象是不是很费事
    因此我们想到了其他方法,我们可以通过序列化的方式来处理,在内存中通过字节流的拷贝来实现。
    也就是把小明写到一个字节流中,再从字节流中读出来,这样就可以重建一个新对象了,这个对象跟小明不存在引用共享的问题,相当于深拷贝一个对象。

    代码如下

    class CloneUtils{
        // 拷贝一个对象
        public static <T extends Serializable> T clone(T obj){
            // 拷贝产生的对象
            T clonedObj = null;
            try {
                // 读取对象字节数据
                ByteArrayOutputStream baos = new ByteArrayOutputStream();
                ObjectOutputStream oos = new ObjectOutputStream(baos);
                oos.writeObject(obj);
                oos.close();
                // 分配内存空间,写入原始对象,生成新对象
                ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
                ObjectInputStream ois = new ObjectInputStream(bais);
                // 返回新对象,进行类型转换
                clonedObj = (T) ois.readObject();
                ois.close();
            } catch (IOException e) {
                e.printStackTrace();
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            }
            return clonedObj;
        }
    }
    

    当然,传入的类要实现Serializable.

    今天的文章结束了~
    Best Wish to you

  • 相关阅读:
    repeater绑定li实现不同样式
    fckeditor 上传图一直显示进度条
    Repeater 获取 DataItem 属性值
    js让显示层居中且有遮挡层(IE,火狐,Chrome均可)
    自定义控件学习(一)
    asp.net做系统时,经典的上左右Iframe
    const与readonly
    如何设置制定按钮为希望响应回车的真正按钮
    domestic的定义
    ebay api(解决固价与拍卖异常问题)
  • 原文地址:https://www.cnblogs.com/lwhblog/p/12588391.html
Copyright © 2011-2022 走看看