java序列化简述

来源:互联网 发布:java方法继承 编辑:程序博客网 时间:2024/06/10 04:18

前段时间同事发布了一个日常,发布OK之后观察没有问题,但是下午有个团队就照过来了,说是我们传递过去的消息发序列化失败,查了很长时间,最后定位是hession的版本存在冲突,以前是hession的3.x版本,应用中依赖了另外一个jar包,这个jar包简介依赖了hession的4.x版本,所以序列化出现问题,所以这篇文章打算扫盲一下。

 

通过网络传输的对象(网络接口上的参数、返回值类型、会抛出的异常类),必须实现Serializable接口,或者父类已经实现序列化接口。

 

         java对象序列化不仅保留一个对象的数据,而且递归保存对象引用的每个对象的数据。可以将整个对象层次写入字节流中,可以保存在文件中或在网络连接上传递。利用对象序列化可以进行对象的“深复制”,即复制对象本身及引用的对象本身。序列化一个对象可能得到整个对象序列。

    java 序列化比较简单,通常不需要编写保存和恢复对象状态的定制代码。实现java.io.Serializable接口的类对象可以转换成字节流或从字节流恢复,不需要在类中增加任何代码。只有极少数情况下才需要定制代码保存或恢复对象状态。这里要注意:不是每个类都可序列化,有些类是不能序列化的,例如涉及线程的类与特定JVM有非常复杂的关系。

序列化机制:

 

     序列化分为两大部分:序列化和反序列化。 序列化是这个过程的第一部分,将数据分解成字节流,以便存储在文件中或在网络上传输。反序列化就是打开字节流并重构对象。对象序列化不仅要将基本数据类型转换成字节表示,有时还要恢复数据。恢复数据要求有恢复数据的对象实例。ObjectOutputStream中的序列化过程与字节流连接,包括对象类型和版本信息。反序列化时,JVM用头信息生成对象实例,然后将对象字节流中的数据复制到对象数据成员中。

 

如果你写过类实现了Serializable 接口,那肯定收到过这样的警告提示,“The serializable class xxx does not declare a static finalserialVersionUID field of type long

SerrialVersionUID被用来作为序列化类的版本控制,如果你没有明确的生命序列化ID,那么JVM会根据类中的信息自动的为你生成一个。但是这个默认的ID对于class文件的比较敏感,且可能在不同的JVM中不同,有可能在反序列化的时候出现异常。如果没有显式赋值,也在你看不见觉察不到的情况下,在你增减了field/修改了定义的情况下,serialVersionUID已被改变,这时网络两端就对接不上而悲剧了。没定义serialVersionUID,而又发生了serialVersionUID变化,网络两端只有所有机器都停掉,并且先后起有顺序时,才能不出丝毫差错。

 

     如果一个类没有序列化,通过ObjectOuputStream进行写操作(),会抛出异常信息“java.io.NotSerializableException”。

 

例如下面代码:
FileOutputStream fs = new FileOutputStream(new File("d:\\java.txt"))
ObjectOutputStream oos = new ObjectOutputStream(fs);
oos.writeObject(user);
读取序列化之后的文件,
InputStream input = new FileInputStream(new File("d:\\java.txt"));
ObjectInputStream ois = new ObjectInputStream(input);
UserDO user = (UserDO)ois.readObject();
  

Externalizable实现了Serializable接口,如果一个类实现了Externalizable接口,则累的序列化以及发序列化则由自己完全控制。这时候在通过Object 进行序列化的时候,会调用类自己实现的writeExternal()以及readExternal()方法。

 

序列化时,类的所有数据成员应可序列化,除了声明为transient的成员。将变量声明为 transient类型就是告诉JVM成员变量dtToday将不被序列化。将数据成员声明为transient后,序列化过程就无法将其加进对象字节流中。后面数据反序列化时,要重建数据成员(因为它是类定义的一部分),但dtToday将不包含任何数据,因为这个数据成员不向流中写入任何数据。

 

不要序列化大数据对象/十分复杂对象,一般long/int/String/Map/List/Array等常见类组成的对象就已能解决问题,最好不要在本应用的业务接口传递/返回另一人主导业务/结构的对象。不是建议不要用ArrayList,只是要注意ArrayList经过网络后可能顺序不一样。两需一一对应的List,经过网络后不一定一一对应。List中有零星的null,可能会给别人造成麻烦。

 

 

原创粉丝点击