JAVA 深层拷贝 DeepCopy的使用详解

 更新时间:2013年07月19日 11:46:50   作者:  
最近需要用到比较两个对象属性的变化,其中一个是oldObj,另外一个是newObj,oldObj是newObj的前一个状态,所以需要在newObj的某个状态时,复制一个一样的对象,由于JAVA不支持深层拷贝,因此专门写了一个方法

方法实现很简单,提供两种方式:
一种是序列化成数据流,前提是所有对象(对象中包含的对象...)都需要继承Serializable接口,如果都继承了那很容易,如果没有继承,而且也不打算修改所有类,可以用第二种方式。

第二种是将对象序列化为json,通过json来实现拷贝,这种方式需要用到net.sf.json.JSONObject。
具体代码如下:

复制代码 代码如下:

    public class DeepCopy { 
        /**
         * 深层拷贝
         * 
         * @param <T>
         * @param obj
         * @return
         * @throws Exception
         */ 
        public static <T> T copy(T obj) throws Exception { 
            //是否实现了序列化接口,即使该类实现了,他拥有的对象未必也有... 
            if(Serializable.class.isAssignableFrom(obj.getClass())){ 
                //如果子类没有继承该接口,这一步会报错 
                try { 
                    return copyImplSerializable(obj); 
                } catch (Exception e) { 
                    //这里不处理,会运行到下面的尝试json 
                } 
            } 
            //如果序列化失败,尝试json序列化方式 
            if(hasJson()){ 
                try { 
                    return copyByJson(obj); 
                } catch (Exception e) { 
                    //这里不处理,下面返回null 
                } 
            } 
            return null; 
        } 

        /**
         * 深层拷贝 - 需要类继承序列化接口
         * @param <T>
         * @param obj
         * @return
         * @throws Exception
         */ 
        @SuppressWarnings("unchecked") 
        public static <T> T copyImplSerializable(T obj) throws Exception { 
            ByteArrayOutputStream baos = null; 
            ObjectOutputStream oos = null; 

            ByteArrayInputStream bais = null; 
            ObjectInputStream ois = null; 

            Object o = null; 
            //如果子类没有继承该接口,这一步会报错 
            try { 
                baos = new ByteArrayOutputStream(); 
                oos = new ObjectOutputStream(baos); 
                oos.writeObject(obj); 
                bais = new ByteArrayInputStream(baos.toByteArray()); 
                ois = new ObjectInputStream(bais); 

                o = ois.readObject(); 
                return (T) o; 
            } catch (Exception e) { 
                throw new Exception("对象中包含没有继承序列化的对象"); 
            } finally{ 
                try { 
                    baos.close(); 
                    oos.close(); 
                    bais.close(); 
                    ois.close(); 
                } catch (Exception e2) { 
                    //这里报错不需要处理 
                } 
            } 
        } 

        /**
         * 是否可以使用json
         * @return
         */ 
        private static boolean hasJson(){ 
            try { 
                Class.forName("net.sf.json.JSONObject"); 
                return true; 
            } catch (Exception e) { 
                return false; 
            } 
        } 

        /**
         * 深层拷贝 - 需要net.sf.json.JSONObject
         * @param <T>
         * @param obj
         * @return
         * @throws Exception
         */ 
        @SuppressWarnings("unchecked") 
        public static <T> T copyByJson(T obj) throws Exception { 
            return (T)JSONObject.toBean(JSONObject.fromObject(obj),obj.getClass()); 
        } 
    } 

只需要调用copy方法就行。

相关文章

  • Java 14 发布了,你还会使用Lombok?

    Java 14 发布了,你还会使用Lombok?

    2020年3月17日发布,Java正式发布了JDK 14 ,目前已经可以开放下载。在JDK 14中,共有16个新特性,本文主要来介绍其中的一个特性:JEP 359: Records,需要的朋友可以参考下
    2020-04-04
  • Java中LocalDate日期格式转换(使用系统时区)

    Java中LocalDate日期格式转换(使用系统时区)

    本文主要介绍了Java中LocalDate日期格式转换(使用系统时区),文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2007-02-02
  • Java反射获取实例的速度对比分析

    Java反射获取实例的速度对比分析

    这篇文章主要介绍了Java反射获取实例的速度对比分析,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2020-09-09
  • @MapperScan扫描包里混有@Service等问题如何解决

    @MapperScan扫描包里混有@Service等问题如何解决

    这篇文章主要介绍了@MapperScan扫描包里混有@Service等问题如何解决,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-03-03
  • logback StatusListener的定义方法源码解读

    logback StatusListener的定义方法源码解读

    这篇文章主要为大家介绍了logback StatusListener的定义方法源码解读,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-11-11
  • 学会IDEA REST Client后就可以丢掉postman了

    学会IDEA REST Client后就可以丢掉postman了

    这篇文章主要介绍了学会IDEA REST Client后就可以丢掉postman了,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2019-12-12
  • play for scala 实现SessionFilter 过滤未登录用户跳转到登录页面

    play for scala 实现SessionFilter 过滤未登录用户跳转到登录页面

    这篇文章主要介绍了play for scala 实现SessionFilter 过滤未登录用户跳转到登录页面的相关资料,需要的朋友可以参考下
    2016-11-11
  • Java编程实现判断网上邻居文件是否存在的方法

    Java编程实现判断网上邻居文件是否存在的方法

    这篇文章主要介绍了Java编程实现判断网上邻居文件是否存在的方法,涉及Java针对路径转换及字符串操作的相关技巧,需要的朋友可以参考下
    2015-10-10
  • IDEA2020.2.3

    IDEA2020.2.3 "reading maven projects"卡住的问题

    这篇文章主要介绍了IDEA2020.2.3 "reading maven projects"卡住的问题及问题原因探究,通过多种方法给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友参考下吧
    2020-10-10
  • SpringBoot 启动方法run()源码解析

    SpringBoot 启动方法run()源码解析

    这篇文章主要介绍了SpringBoot 启动方法run()源码赏析,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2021-03-03

最新评论