Java 序列化详解及简单实现实例
一、序列化
序列化定义:序列化是将对象状态转换为可保持或传输的格式的过程。与序列化相对的是反序列化,它将流转换为对象。这两个过程结合起来,可以轻松地存储和传输数据。
目的:
- 以某种存储形式使自定义对象持久化
- 将对象从一个地方传递到另一个地方
二、Java序列化
一个对象能够序列化的前提是实现Serializable接口。Serializable接口没有方法,更像是个标记。有了这个标记的Class就能被序列化机制处理。如下:
classmyPointimplementsSerializable{
}
JAVA反序列化不会调用任何构造器
序列化的控制:Externalizable。读写都交给你
- 要在方法writeExternal写入序列化的参数
- 要在方法readExternal读取反序列化的值
- 要有默认的构造方法(readExternal执行完成,再执行默认的构造器)
voidwriteExternal(ObjectOutputout)throwsIOException;
voidreadExternal(ObjectInputin)throwsIOException,ClassNotFoundException;
publicclassPointimplementsExternalizable{
privateinta;
privateintb;
publicPoint(inta,intb){
this.a=a;
this.b=b;
}
publicPoint(){
}
publicStringtoString(){
returna+","+b;
}
publicvoidwriteExternal(ObjectOutputout)throwsIOException{
out.write(a);
out.write(b);
}
publicvoidreadExternal(ObjectInputin)throwsIOException,
ClassNotFoundException{
a=in.read();
b=in.read();
}
publicstaticvoidmain(String[]args)throwsIOException,
ClassNotFoundException{
Stringfile="d://1.txt";
Pointp=newPoint(1,2);
System.out.println(p);
FileOutputStreamfos=newFileOutputStream(file);
ObjectOutputStreamoos=newObjectOutputStream(fos);
oos.writeObject(p);
FileInputStreamfis=newFileInputStream(file);
ObjectInputStreamois=newObjectInputStream(fis);
Pointpp=(Point)ois.readObject();
System.out.println(pp);
}
}
- transient关键字关闭序列化自动进行。
- 不管你选择了哪种序列化形式,都要为自己编写的每个可序列化的类声明一个显示的序列版本UID(serialversionUID)
三、序列化的问题
在effectiveJava中列举出了java序列化要注意的一些问题:
1.谨慎地设计实现Serializable接口
- 实现发布了就是一种承诺
- 如果一个类是为继承设计的,在‘允许子类实现Serializable接口'与‘禁止子类实现Serializable接口'取一个折中的方案是:提供一个可访问的无参构造器
2.保护性地编写readObject()方法,因为readObject()是构建实例的入口。
不保护可能出现构建了不满足要求的实例
3.考虑自定义的序列化形式
- 逻辑内容与物理表示法
- 如果一个对象的‘物理表示法'等同于它的‘逻辑内容',可能就适用于使用默认的序列化形式。
- 如果有更好的‘物理表示法'在表示‘逻辑内容'则可以自定义序列化形式。
publicclassStringListimplementsSerializable{
privatetransientintsize=0;
privatetransientEntityhead=null;
publicfinalvoidadd(Stringstr){
//...
}
privatestaticclassEntity{
Stringdata;
Entitynext;
Entityprevious;
}
privatevoidwriteObject(ObjectOutputStreams)throwsIOException{
s.defaultWriteObject();
s.write(size);
for(Entitye=head;e!=null;e=e.next){
s.writeObject(e.data);
}
}
privatevoidreadObject(ObjectInputStreams)throwsIOException,
ClassNotFoundException{
s.defaultReadObject();
intnum=s.read();
for(inti=0;i
四、序列化代理模式
序列化机制提供的钩子函数有:
writeReplacewriteObject readObject readResolve
- writeReplace:序列化的时候替换所要序列化的对象。
- writeObject:写入序列化的对象
- readObject:读取序列化的对象
- readResolve:最后返回序列化对象
importjava.io.InvalidObjectException;
importjava.io.ObjectInputStream;
importjava.io.Serializable;
importjava.util.Date;
publicfinalclassPeriodimplementsSerializable{
privatestaticfinallongserialVersionUID=100L;
privatefinalDatestart;
privatefinalDateend;
publicPeriod(Datestart,Dateend){
this.start=newDate(start.getTime());
this.end=newDate(end.getTime());
if(this.start.compareTo(this.end)>0){
thrownewIllegalArgumentException(start+"after"+end);
}
}
publicDatestart(){
returnnewDate(start.getTime());
}
publicDateend(){
returnnewDate(end.getTime());
}
publicStringtoString(){
returnstart+"-"+end;
}
//不给
privateObjectwriteReplace(){
returnnewSerializationProxy(this);
}
privatevoidreadObject(ObjectInputStreamstream)
throwsInvalidObjectException{
thrownewInvalidObjectException("proxyrequest");
}
privatestaticclassSerializationProxyimplementsSerializable{
privatefinalDatestart;
privatefinalDateend;
SerializationProxy(Periodp){
this.start=p.start;
this.end=p.end;
}
privateObjectreadResolve(){
returnnewPeriod(start,end);
}
privatestaticfinallongserialVersionUID=1000L;
}
}
五、序列化算法
- 将对象实例相关的类元数据输出。
- 递归地输出类的超类描述直到不再有超类。
- 类元数据完了以后,开始从最顶层的超类开始输出对象实例的实际数据值。
- 从上至下递归输出实例的数据
感谢阅读,希望能帮助到大家,谢谢大家对本站的支持!