概念 1 2 序列化:将结构对象转为字节序列的过程。
为什么要序列化: 简单的说序列化是用来通信的,为了跨进程传递格式化数据(byte流)。
序列化原理: 序列化和反序列化的处理是通过ObjectInputStream和ObjectOutputStream实现的,验证如下:
定义一个Account类如下,怕篇幅过长删除了不必要的空格
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 public  class  Account  implements  Serializable  private  static  final  long  serialVersionUID = -547309094426427798L ;private  Long id;private  String account;transient  private  String password;private  String email;@Override public  String toString ()  return  "Account{"  +"id="  + id +", account='"  + account + '\''  +", password='"  + password + '\''  +", email='"  + email + '\''  +'}' ;
定义序列化和反序列化的工具类
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 37 38 39 40 public  class  SerializableUtil  public  static  void  serialize (Object obj,String fileName)  throws  IOException new  FileOutputStream(fileName);new  ObjectOutputStream(fos);public  static  Object deserialize (String fileName)  throws  Exception new  FileInputStream(fileName);new  ObjectInputStream(fis);return  object;public  static  void  main (String[] args)  throws  Exception new  Account();1L );"chase" );"wfp_chase@163.com" );"********" );"account" );"account" );
验证结果如下:
1 2 3 4 5 6 7 8 9 10 在实现Serializable  接口的情况下
在没有实现Serializable的情况报错的原因如下:
因为是在序列化的过程中报错的,可以从oos.writeObject(obj); 方法中断点找原因
在源码中可以看到 obj 不属于 以上条件的任何一种,所以只能抛出NotSerializableException异常。
serialVersionUID 作用: 在序列化中是通过类的serialVersionUID来验证版本一致的
字节流中的serialVersionUID于本地相应实体类的serialVersionUID进行比较,如果一致,则可以反序列化,否则会报InvalidCastException异常。所以在创建类时如果需要进行序列化操作,最好是显示设置serialVersionUID的值。
过程: 在进行序列化时,如果serialVersionUID在类中不显示设置,会根据类的诸多相关的信息(属性、名称、方法等等)自动计算生成一个。由于计算规则是固定的,所以在编译后的class文件没有发生变化时,serialVersionUID 的值始终是一样的
验证: 如果将Account中的serialVersionUID注释掉,再将原来的accout反序列化时就会报如下错误
1 Exception in thread "main" java.io.InvalidClassException: test.serializable.Account; local class incompatible: stream classdesc serialVersionUID = 7640500986923754437, local class serialVersionUID = -547309094426427798
部分源码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 public  long  getSerialVersionUID ()  if  (suid == null ) {new  PrivilegedAction<Long>() {public  Long run ()  return  computeDefaultSUID(cl);return  suid.longValue();
序列化中继承和静态变量序列化 继承问题 
如果父类实现序列化,子类自动实现序列化,不需要显式实现Serializable接口。 
如果一个子类实现了 Serializable 接口,其父类都没有实现 Serializable 接口,要想将父类对象也序列化,就需要让父类也实现Serializable 接口。 
 
原因:
静态变量序列化 序列化保存的是对象的状态,静态变量属于类的状态,因此 序列化并不保存静态变量。
Java序列化之Externalizable 使用Externalizable时,需要实现如下两个方法,用于控制序列化和反序列化的类中属性字段,需要注意的是 transient 关键字将不会在这种情况下起作用。
void writeExternal(ObjectOutput out) throws IOException;
void readExternal(ObjectInput in) throws IOException, ClassNotFoundException;
Externalizable 是继承了 Serializable 所以在序列化时本质和实现是一样的都是通过ObjectOutputSteam和ObjectInputStream处理的。
1 2 3 4 public  interface  Externalizable  extends  java .io .Serializable  void  writeExternal (ObjectOutput out)  throws  IOExceptionvoid  readExternal (ObjectInput in)  throws  IOException, ClassNotFoundException