这里写目录标题
如果不实现Cloneable接口,使用对象的clone方法会抛CloneNotSupportedException异常。
一、浅拷贝-- clone()方法
接口Cloneable,实现该接口的类都会具备被拷贝的能力,同时拷贝是在内存中进行,在性能方面比我们直接通过new生成对象来的快,特别是在大对象的生成上,使得性能的提升非常明显。
clone()方法是使用Object类的clone()方法【非java方法】,但是该方法存在一个缺陷,它并不会将对象的所有属性全部拷贝过来,而是有选择性的拷贝,基本规则如下:
(1、 基本类型
如果变量是基本很类型,则拷贝其值,比如int、float等。
(2、 对象
如果变量是一个实例对象,则拷贝其地址引用,也就是说此时新对象与原来对象是公用该实例变量。无论对象内部什么类型,拷贝后的和拷贝前的是同一个位置,拷贝的只是地址。
(3、 String字符串
若变量为String字符串,则拷贝其地址引用。但是在修改时,它会从字符串池中重新生成一个新的字符串,原有对象保持不变【无论修改旧的还是新的,都不会互相干扰】。
二、浅拷贝–Cglib包的BeanCopier类
采用Cglib包的BeanCopier类实现对象复制,对象需要setting和getting方法。注意的是,内部对象拷贝还是地址引用,无论内部对象是基本类型还是String类型。
//采用BeanCopier类实现对象复制。create是初始化。建立两个对象字段的关系
BeanCopier beanCopierTemp = BeanCopier.create(source, target, false);
//根据新对象class信息得到类实例
Z target = tClass.newInstance();
//将源对象的信息copy到新的类实例中。注意,内部类还是拷贝的是地址
beanCopier.copy(source, target, null);
三、深拷贝–字节流拷贝
内存中通过字节流拷贝。
原理:对象字节数组(拷贝)对象 【要求Bean对象必须序列化】
public static <T extends Serializable> T clone(T obj){
T cloneObj = null;
try {
//写入字节流 【先是向硬盘等位置写入数据】
ByteArrayOutputStream out = new ByteArrayOutputStream();
//obs相当于将对象序列化转换为文件保存,最终有out来Byte数组获取到数据
ObjectOutputStream obs = new ObjectOutputStream(out);
obs.writeObject(obj);
obs.close();
//分配内存,写入原始对象,生成新对象 【从如硬盘等位置读取数据,写入到内存】
ByteArrayInputStream ios = new ByteArrayInputStream(out.toByteArray());
ObjectInputStream ois = new ObjectInputStream(ios);
//返回生成的新对象
cloneObj = (T) ois.readObject();
ois.close();
} catch (Exception e) {
e.printStackTrace();
}
return cloneObj;
}
四、Java.io.Serializable接口
凡是一个接口中没有任何定义,就被称为标记接口。
不实现此接口的类的任何字段(属性)都不能序列化和反序列化。