对象序列化可以将任何对象写出到流中,并在之后将其读回
要序列化的对象的类必须实现 Serializable
接口,Serializable接口没有任何方法
序列化的一个重要作用是通过网络将对象传送到另一台计算机,因为序列化用序列号代替内存地址,每个对象都有一个序列号
类中静态成员不会被序列化,因为静态成员属于类级别,序列化只是序列化对象,所以序列化写入的只有非瞬态
和非静态
数据域
读取对象的顺序与写入时的顺序
要一致
某些数据域不想或不能被序列化,用 transient (瞬态)
标记,如:
序列化和反序列化中需要特殊处理的行为可以使用下列签名的方法(对某些数据域)
private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException;private void writeObject(ObjectOutputStream out) throws IOException;//例子public class LabelPoint implements Serializable{ private String label; private transient Point2D.Double point; ... private void writeObject(ObjectOutputStream out) throws IOException { out.defaultWriteObject(); out.writeDouble(point.getX()); out.writeDouble(point.getY()); } private void readObject(ObjectInputStream in) throws IOException,ClassNotFoundException { in.defaultReadObject(); double x = in.readDouble(); double y = in.readDouble(); point = new Point2D.Double(x,y); }}readObject和writeObject方法不关心超类数据和其他类的信息。readExternal和writeExternal方法对包括超类数据在内的整个对象的存储和恢复负责(接口不一样)
public class Foo implements Externalizable{ private int a; private String b; private Date c; public void readExternal(ObjectInputStream in) throws IOException { a = in.readInt(); b = in.readString(); c = new Date(in.readLong()); } public void writeExternal(ObjectOutputStream out) throws IOException { out.writeInt(a); out.writeString(b); out.writeLong(c.getTime()); }}类型安全的枚举和单例模式的类需要添加readResolve方法
,因为此时默认的序列化机制不起作用。
readResolve方法在对象被序列化之后被调用,必须返回一个对象,此对象会成为之后readObject方法的返回值,如:
class Foo implements Serializable{ public static final Foo TEST1=new Foo(1); public static final Foo TEST2=new Foo(2); private int value; private Foo(int v){value=v;}}//TEST1是单例Foo original = Foo.TEST1;ObjectOutputStream out = ...out.writeObject(foo1);out.close();//此时saved和original不是同一个对象,errorObjectInputStream in = ...Foo saved = (Foo)in.readObject();//Foo类中添加readResolveprotected Object readResolve() throws ObjectStreamException{ if(value==1) return Foo.TEST1; if(value==2) return Foo.TEST2; return null; //这一步不应该发生}类可以对其早期版本进行兼容,但必须有这个类早期版本的指纹,即 serialVersionUID
,此静态数据成员被放在某个类,则序列化系统就可以读入这个类的对象的不同版本(这个类的所有较新版本都必须把 serialVersionUID 定义为与初始版本相同)
如果这个类只有方法发生了变化,则读入新对象数据时不会有问题;如果数据域发生了变化,则可能有问题,对象流将尽力将流对象转换成这个类的当前版本,做法如下(不处理瞬态和静态数据域):
对于数据域名字匹配,类型不匹配,不会转换流中对象具有当前版本没有的数据域,则忽略这些数据域当前版本具有流对象中没有的数据域,则这些新添加的数据域设置成他们的默认值,对象为null,数字为0,boolean为false新闻热点
疑难解答