# __ .______ __ __ .______ .___________. ______ ______ .___ ___. # | | | _ \ | | | | | _ \ | | / | / __ \ | \/ | # | | | |_) | | |__| | | |_) | `---| |----` | ,----'| | | | | \ / | # | | | ___/ | __ | | ___/ | | | | | | | | | |\/| | # | | | | | | | | | | | | __ | `----.| `--' | | | | | # |__| | _| |__| |__| | _| |__| (__) \______| \______/ |__| |__| # ""$o o$"" ""$o o$" o "$""""o "o $" o""" $" "$o "$o" $o " $ o$" "$o $$$o$$$$o$$$$ $" "oooo o "" ""$$$$$$$$""o"" oo oooo" "$$$$$$oo"oo$$$o" o$$$$oo" o$$$o "o$$$$$$$ "$ $$$$$$$$$oo o$$$$$$$$$o"$" $ $$$ $$$$$$ o$$$$$$ "$$o"o $ $$$$o $$$$$$ $$$$$$$ $$$$o"o $ $$$$$ $$$$$" "$$$$$ $$$$$$ $ $o""""" """" """ """"""$" $ o$$$$$"""$$$$$"$$$$$""$$$$$ooo"o $ o"$o $$$$$$$$oo$$$$$$$$o $$"" $ oo$ "$$$$$$$$$$$$$$$$$$$$" o" o $oo o$$$"$ $$o"o $$$$$$$"" "$$$$$$$ o$$ $$$$o IPHPT BUG o$$$$" $ $$$$ o "$$$$$oo o$$$$$$ "o$$$$ $ $$$$$ o$$"" $ $$$$$o" "$$$$$$$$$$$$$ o o$$$$$o$ "" $$ $$" $ $$$" o"o$$$$$$$$$$$$ " "$$$ $ $$o o$$ "o $$ " $$$$$$$$$$$"o "$$ $ $$$ $$$ oo$ $ o""$$""$$$o " $"o$o $$$o o$$$$ o$$$"o"$oo$$$$o" o $o $$$$$oo$ $$$$o $$$$ $$$$ $$$$" $ $$$$$"" $$ o$$$ """$$$$"o" "$$$o "$$$o $$$" o """ $ $$$oo $$$$o" $$ o$$$"o" """"$ o$$$ o$" $$$ $ "$"" o$"o"$$o$$$$ "$$"o" o$$ "$oo $ " $$o $ "oo$"o$$$"o$o"$$$$o" o" $$$ ""$o $$ $$$o "o$$o$"$$"$$o$$o$$"$$o" $$$ ""o $$$ ""$$$ $$$$$$ $$$$ $" $$$$ $$ $$$$ $$$$"$$$o$ $"" $$$ $$$$ "$$$ """ $$$$ $$"" "$$ oo$" $ooo $ "$$ Java 序列化   -  知芯

Java 序列化

对象序列化保存对象的“状态”,也就是成员变量,不会关注类中的静态变量和方法。如果对象的成员是对象则递归处理。

1. 使用场景

  • 将内存中的对象状态保存到文件或数据库;
  • 在网络上用socket传输对象;
  • 通过RMI传输对象。

2. Serializable接口

  • 任何需要被序列化的对象都需要实现此接口,此接口完全为空,只用来说明此接口实现类的对象可以被序列化。
  • 如果父类实现此接口,子类自动可序列化,不用显示实现此接口;
  • 如果子类实现而父类没实现,那么父类必须有无参构造方法(如果自定义了有参构造函数,就必须写出无参构造函数;都没有时默认生成无参构造函数),此时反序列化得到的对象的父类变量可能和当前的父类变量不同。
  • StringEnum数组可序列化,此外必须实现了此接口,才可序列化。

3. 对象读写

序列化工作通过ObjectOutputStreamObjectInputStream来完成的,使用writeObjectreadObject对对象进行读写,对于基本类型,可采用readInt|weiteInt等接口读写。

4. transient关键字

修饰类的变量使得序列化过程忽略该变量(修饰static变量不报错,没意义),此关键字标识的引用会以null返回,基本类型以对应的默认值返回。

5. serialVersionUID

Java序列化机制通过serialVersionUID判断类的版本一致性,同样的类如果serialVersionUID不同不能互相反序列化。InvalidClassException

6. 存储规则

  • 同一个对象多次存入一个文件,只是多存储一份引用;
  • 修改后的对象存入同一个文件,判断文件中已有该对象,后面只存储引用,依次读出的对象都是第一次的对象,没有修改的值。

writeObjectreadObject

  private void writeObject(ObjectOutputStream out){
      out.defaultWriteObject();
      out.writeInt(area); 
  }
  private void readObject(ObjectInputStream in){
      in.defaultReadObject();
      area = in.readInt();
  }
  • 序列化类定义这两个方法必须是private(使用反射调用的)。
  • writeInt是将area单独保存到文件,而非保存成对象的属性,readInt是单独读取并设置成属性。
  • 序列化对象时,如果对象有writeObject方法,则调用,否则执行默认序列化规则;反序列化同理。

7. Externalizable接口

Externalizable继承于Serializable,当使用该接口时,序列化的细节需要由程序员去完成。

  • 实现writeExternalreadExternal方法
  • 序列化类必须有public无参构造函数(readExternal先调用无参构造函数创建对象,再自行赋值)
  • 生成文件存储格式和Serializable不太相同

8. readResolve()

用于解决反序列化后违背单例的问题。

无论是实现Serializable接口,或是Externalizable接口,当从I/O流中读取对象时,readResolve()方法都会被调用到。实际上就是用readResolve()中返回的对象直接替换在反序列化过程中创建的对象。

测试发现,使用`Externalizable时,此方法readExternal之后调用;使用Serializable时,也是在readObject之后调用。

9. 缺点

  • 无法跨语言
  • 序列化后的码流较大
  • 序列化性能较低

欢迎转载,但请附上本文地址: http://www.codeyourlife.cn/detail/48/

理想和现实,他们是两种人,而我处于两者之间。有时激情昂扬认为自己能改变世界,仔细想来,大多数人注定平凡。