[编写高质量代码:改善java程序的151个建议]建议43 避免对象浅拷贝; 建议44:推荐使用序列化实现对象的深拷贝

拷贝clone() 与new的区别?

 
浅拷贝
实现clone()方法的时候,
如果用默认的super.clone()方法会调用Object类的默认拷贝,缺陷:不会把所有的属性全部拷贝一份,拷贝规则:
(1)基本类型,拷贝其值
(2)对象:
拷贝引用地址,新拷贝的对象和原有对象共享该实例变量,不受访问权限控制。
(3)String字符串:拷贝的是引用,但有点特殊,在修改时,会从字符串池中重新生成新的字符串。原有的字符串内容保持不变,故可以认为String是一个基本类型。
 
为了实现深拷贝:
在clone()方法的重载时,
在设置属性时new一个对象出来。这样拷贝出来的和原来的不会共有一份引用。
 
建议44.推荐使用序列化实现对象的深拷贝
 
实现Cloneable接口实际上就具备了拷贝能力,但如果一个项目中有大量的对象是通过拷贝生成的,每个类都写一个clone(0方法,并且还要深拷贝?那就非常麻烦了。
方法:
通过序列化方式来处理,在内存中通过字节流的拷贝来实现,即把母体对象写到一个字节流中,再从字节流中将其读出来。该新对象和母对象之间不存在引用共享的问题,也就相当于深拷贝了一个新对象。
 
public class ColoneUtils{
    public static <T extens Serializable> T clone(T obj){
        T cloneObj = 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);
            cloneObj = (T)ois.readObject();
            ois.close();
        }catch(Exception e){
            e.printStackTrace();
        }
        return cloneObj;
 
    }
}
 
当然,被拷贝的对象必须实现Serializeable接口,否则没办法拷贝的。
还要注意:
(1)对象的内部属性都是可序列化的
(2)方法和属性的特殊修饰符。
@transient
瞬态变量,不进行序列化的变量。
 
当然 Apache 的commons工具包中SerializationUtils类。没用过。
原文地址:https://www.cnblogs.com/akingseu/p/3485793.html