什么是序列化
序列化是指将一个对象转换为一个一连串的字节描述的过程。而反序列化是将这个一连串的字节数据转化为对象的过程。在一个分布式的环境中,经常需要将一个Object从一端传递到网络的另外一端,此时就需要在发送端序列化之后,经过网络将字节流传递到另一端,对端再将字节流转换为对象。场景
持久化存储,将对象持久化为流存储到对象或缓存中;
远程过程调用,将序列化之后的流经过网络传输解析;而对开发人员来说,底层的控制协议都被屏蔽了,它们看到了一个在同一个虚拟机内调用的效果。
如何序列化对象
只要实现java.io.Serializable接口的对象都可以被JVM序列化,java.io.Serializable是一个标记接口,没有定义任何方法,它只是为了声明一个对象是可以被序列化的。例如:
public class User implements Serializable{ private long id; private String name; }
Java中,ObjectOutputStream和ObjectInputStream负责序列化java对象,通过ObjectOutputStream的writeObject方法来将一个对象写入到流中,通过ObjectInputStream的readObject方法将一个对象从流中读出,例如:
ByteArrayOutputStream bo = new ByteArrayOutputStream(); ObjectOutputStream out = new ObjectOutputStream(bo); out.writeObject(test); byte[] bytes = bo.toByteArray(); out.flush(); ObjectInputStream input = new ObjectInputStream(new ByteArrayInputStream(bytes)); KryoTest s = (KryoTest)input.readObject(); AssertUtil.assertNotNull(s); input.close();默认对象所有的非静态和非瞬时的域都会被包含进来,而与域的声明没有关系。此时有两个办法来保证某些域不被序列化。第一种就是使用Transient关键字,将域声明为瞬时的,此时序列化将不会包含瞬时域。另外一种方式是通过serialPersistentFields来声明要被序列化的域,例如如果只序列化Person的name域:
private static final ObjectStreamField[] serialPersistentFields = { new ObjectStreamField("name", String.class) };
自定义序列化
自定义序列化是通过在对象中声明四个私有方法来完成的。这四个方法分别是:private void writeObject(java.io.ObjectOutputStream out) throws IOException; private void readObject(java.io.ObjectInputStream in) throws IOException, ClassNotFoundException; private Object readResolve() throws ObjectStreamException; private Object writeReplace() throws ObjectStreamException;通过writeObject和readObject方法可以自定义序列化逻辑,例如额外序列化一个字段等。
而通过writeReplace和readResolve方法可以在写对象前和读取流之后对操作对象做自定义修改。这四个方法的执行顺序是writeReplace->writeObject->readObject->readResolve
其他序列化工具
java的序列化性能一直都不被恭维。而当前市面上也有很多开源的序列化工具,例如kyro,protostuff等,这些开源的序列化工具的性能大大超过了java本身的序列化性能。
以kyro举例,将同一个对象序列化反序列化50000次,得出的耗时时间比:
Output output = new Output(1, 4096); kryo.writeObject(output, test); byte[] bb = output.toBytes(); output.flush(); Input input = new Input(bb); KryoTest s = (KryoTest) kryo.readObject(input, KryoTest.class); AssertUtil.assertNotNull(s); input.close();
没有评论:
发表评论