clone

  clone的理解

http://blog.csdn.net/cws1214/article/details/52193341

为何要clone

有个对象A,此时需要和其一样的对象B,且修改B不影响A。简单的B=A不行,clone登场。

new和clone

new:本意是分配内存。1、当程序执行到new时,看new后面的操作类型,根据类型分配内存空间。2、调用构造函数,填充对象的各个域,即初始化。3、对象创建结束,将引用(地址)返回给外部。

clone:1、分配内存(和new相似),大小和原对象大小一样。2、将原对象的各个域填充到新对象域中。3、对象呗创建,将引用(地址)返回给外部。

clone使用

复制对象和复制引用

1
2
3
4
5
A a1 = new A();
A a2 = a1; // 是将引用地址给a2.
A a3 = new A();
A a4 = (A)a3.clone(); // clone的新对象地址给a4

浅拷贝和深拷贝


这个对象必须要实现 Cloneable 接口,实现 clone
方法,并且在 clone 方法内部,把该对象引用的其他对象也要 clone 一份。

1
2
3
4
5
6
7
8
9
10
11
12
13
static class Body implements Cloneable{
public Head head;
public Body() {}
public Body(Head head) {this.head = head;}
@Override
protected Object clone() throws CloneNotSupportedException {
Body newBody = (Body) super.clone();
newBody.head = (Head) head.clone();
return newBody;
}
}

实现克隆

1). 实现 Cloneable 接口并重写 Object 类中的 clone()方法;

2). 实现 Serializable 接口,通过对象的序列化和反序列化实现克隆,可以实现真正的深度克隆。

  注意:基于序列化和反序列化实现的克隆不仅仅是深度克隆,更重要的是通过泛型限定,可以检查出要克隆的对象是否支持序列化,这项检查是编译器完成的,不是在运行时抛出异常,这种是方案明显优于使用 Object 类的 clone方法克隆对象。让问题在编译的时候暴露出来总是好过把问题留到运行时。

1
2
3
4
5
6
7
8
9
10
public static <T extends Serializable> T clone(T obj) throws Exception {
ByteArrayOutputStream bout = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(bout);
oos.writeObject(obj);
ByteArrayInputStream bin = new ByteArrayInputStream(bout.toByteArray());
ObjectInputStream ois = new ObjectInputStream(bin);
return (T) ois.readObject();
// 说明:调用 ByteArrayInputStream 或 ByteArrayOutputStream 对象的 close 方法没有任何意义
// 这两个基于内存的流只要垃圾回收器清理对象就能够释放资源,这一点不同于对外部资源(如文件流)的释放
}
文章目录
  1. 1. 为何要clone
  2. 2. new和clone
  3. 3. clone使用
    1. 3.1. 复制对象和复制引用
    2. 3.2. 浅拷贝和深拷贝
  4. 4. 实现克隆
|