利用串行化来做深复制(主要是为了避免重写比较复杂对象的深复制的clone()方法,也可以程序实现断点续传等等功能)
把对象写到流里的过程是串行化(Serilization)过程,但是在Java程序师圈子里又非常形象地称为“冷冻”或者“腌咸菜(picking)”过程;而把对象从流中读出来的并行化(Deserialization)过程则叫做 “解冻”或者“回鲜(depicking)”过程。
应当指出的是,写在流里的是对象的一个拷贝,而原对象仍然存在于JVM里面,因此“腌成咸菜”的只是对象的一个拷贝,Java咸菜还可以回鲜。
在Java语言里深复制一个对象,常常可以先使对象实现Serializable接口,然后把对象(实际上只是对象的一个拷贝)写到一个流里(腌成咸菜),再从流里读出来(把咸菜回鲜),便可以重建对象。
如下为深复制源代码。
1
2
3
4
5
6
7
8
9
10
11
|
public Object deepClone()
{
//将对象写到流里
ByteArrayOutoutStream bo= new ByteArrayOutputStream();
ObjectOutputStream oo= new ObjectOutputStream(bo);
oo.writeObject( this );
//从流里读出来
ByteArrayInputStream bi= new ByteArrayInputStream(bo.toByteArray());
ObjectInputStream oi= new ObjectInputStream(bi);
return (oi.readObject());
}
|
这样做的前提是对象以及对象内部所有引用到的对象都是可串行化的,否则,就需要仔细考察那些不可串行化的对象或属性可否设成transient,从而将之排除在复制过程之外。上例代码改进如下。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
|
class Teacher implements Serializable{
String name;
int age;
public void Teacher(String name, int age){
this .name=name;
this .age=age;
}
}
public class Student implements Serializable{
String name; //常量对象
int age;
Teacher t; //学生1和学生2的引用值都是一样的。
public void Student(String name, int age,Teacher t){
this .name=name;
this .age=age;
this .p=p;
}
public Object deepClone() throws IOException,
OptionalDataException,ClassNotFoundException{ //将对象写到流里
ByteArrayOutoutStream bo= new ByteArrayOutputStream();
ObjectOutputStream oo= new ObjectOutputStream(bo);
oo.writeObject( this ); //从流里读出来
ByteArrayInputStream bi= new ByteArrayInputStream(bo.toByteArray());
ObjectInputStream oi= new ObjectInputStream(bi);
return (oi.readObject());
}
public static void main(String[] args){
Teacher t= new Teacher( "tangliang" , 30 );
Student s1= new Student( "zhangsan" , 18 ,t);
Student s2=(Student)s1.deepClone();
s2.t.name= "tony" ;
s2.t.age= 40 ;
//学生1的老师不改变
System.out.println( "name=" +s1.t.name+ "," + "age=" +s1.t.age);
}
}
|