序列化与反序列化

序列化的意义java

  在考虑系统性能的时候,会考虑序列化。远程通讯的时候,就要考虑序列化。序列化和反序列化是天天都会碰到的问题。就我而言,序列化这个概念基本上一直在听到,可是不多有了解。Java对象的传输、分布式架构、大数据量的工程。
  Java 平台容许咱们在内存中建立可复用的Java 对象,但通常状况下,只有当JVM处于运行时,这些对象才可能存在,因此这些对象的生命周期不会比JVM 的生命周期更长。但在现实应用中,就可能要求在JVM中止运行以后可以保存(持久化)指定的对象,并在未来从新读取被保存的对象。Java 对象序列化就可以帮助咱们实现该功能。
  序列化是把对象的状态信息转化为可存储或传输的形式过程,也就是把对象转化为字节序列的过程称为对象的序列化。
  反序列化是序列化的逆向过程,把字节数组反序列化为对象,把字节序列恢复为对象的过程成为对象的反序列化。
  那么如何去评价一个序列化工具呢?
  评价一个序列化算法优劣的两个重要指标是:序列化之后的数据大小;序列化操做自己的速度及系统资源开销(CPU、内存)。


常见的序列化工具git

Java自己自带的序列化github

  Java自己就有一个序列化工具(实现Serializable接口),可是缺点也是存在的:(1)序列化后数据比较大。(2)其余语言没法识别
  Java自己序列化方法:
  @Override public <T> byte[] serializer(T obj) { ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); ObjectOutputStream objectOutputStream = null; try { objectOutputStream = new ObjectOutputStream(byteArrayOutputStream); objectOutputStream.writeObject(obj); } catch (IOException e) { e.printStackTrace(); } finally { if(objectOutputStream != null) { try { objectOutputStream.close(); } catch (IOException e) { e.printStackTrace(); } } } return byteArrayIutputStream.toByteArray(); } @Override public <T> T deSerializer(byte[] bytes, Class<T> clazz) { ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(bytes); ObjectInput objectInput = null; try { objectInput = new ObjectInputStream(byteArrayInputStream); return (T)objectInput.readObject(); } catch (Exception e) { e.printStackTrace(); } return null; }

  对于一个但愿经过序列化的类,可能会报InvalidClassException,这是由于序列化的类最好加上serialVersionUID,用来让系统判断序列化的可靠性。算法

serialVersionUID 的做用
  Java 的序列化机制是经过判断类的serialVersionUID 来验证版本一致性的。在进行反序列化时,JVM 会把传来的字节流中的serialVersionUID与本地相应实体类的serialVersionUID 进行比较,若是相同就认为是一致的,能够进行反序列化,不然就会出现序列化版本不一致的异常,便是InvalidCastException若是没有为指定的class 配置serialVersionUID,那么java 编译器会自动给这个class 进行一个摘要算法,相似于指纹算法,只要这个文件有任何改动,获得的UID 就会大相径庭的,能够保证在这么多类中,这个编号是惟一的。json

  serialVersionUID 有两种显示的生成方式:
  一是默认的1L,好比:private static final long serialVersionUID = 1L;
  二是根据类名、接口名、成员方法及属性等来生成一个64 位的哈希字段。
  当实现java.io.Serializable 接口的类没有显式地定义一个serialVersionUID 变量时候,Java 序列化机制会根据编译的Class 自动生成一个serialVersionUID 做序列化版本比较用,这种状况下,若是Class 文件(类名,方法明等)没有发生变化(增长空格,换行,增长注释等等),就算再编译屡次,serialVersionUID 也不会变化的。api

  Java对象序列化过程当中,若是序列化获得的对象增长或者减小一个变量,并不会报错,仅仅是某个字段读取不到。对于一个静态变量的序列化,静态变量不会参与序列化。由于序列化保存的是一个对象的状态,而静态变量属于一个类的状态。数组

transient架构

  transient修饰的字段表示不会在序列化过程被保存,他的值在反序列化以后还是类定义的值。也能够手动写到流里面,来绕过序列化框架

序列化与继承分布式

  若是说一个子类实现了序列化,父类没有实现序列化,在子类被反序列化以后,是没法得到父类的值,即子类继承父类已经被定义的那个值是空的。

  若是一个父类实现序列化,那么子类自动实现序列化,不用继承Serializable接口。

  对于同一个对象写入流两次,流里的数据不会加倍,而是增长五个字节(增长新增引用和一些控制信息的空间),由于当流里存在同一个对象的时候,只是会增长一个引用。这算是个优势,节省了存储空间。

序列化实现克隆

  Java对于每一个接口类都具备克隆能力,但只是浅克隆。浅克隆只是新建对象,对原对象的一些变量只是复制它的引用。我实例2 克隆实例1,当实例2改变某个值后,实例1也会改变。深克隆实现Serializable接口,把对象序列化流中,再从流里读出来,这个对象就不是原来的对象了,全部的变量的引用都会新建一个引用。

xml序列化框架

  优势是可读性强,缺点是序列化以后的数据比较大。在技术要求比较高的时候,通常不会用到它。

  代码实例:

public class XmlSerializer { XStream xStream = new XStream(new DomDriver()); public <T> String serializer(T obj) { return xStream.toXML(obj); } public <T> T deSerializer(String bytes, Class<T> clazz) { return (T)xStream.fromXML(bytes); } public static void main(String[] args) { XmlSerializer iSerializer = new XmlSerializer(); User user = new User(); String bytes = iSerializer.serializer(user); user.setName("jolivan"); System.out.println(new String(bytes)); User userNow = iSerializer.deSerializer(bytes,User.class); System.out.println(userNow.getName()); System.out.println(userNow.getAge()); } } ==============输出==================
<serial.User>
  <name>Lushe</name>
  <age>23</age>
</serial.User> Lushe 23

  咱们能够看到,根据数据咱们就知道他是个什么类,里面有啥。可读性很是高。

JSON

  JSON(JavaScript Object Notation)是一种轻量级的数据交换格式,相对于XML 来讲,JSON 的字节流更小,并且可读性也很是好。如今JSON数据格式在企业运用是最广泛的
  JSON 序列化经常使用的开源工具备不少
  1. Jackson (https://github.com/FasterXML/jackson)
  2. 阿里开源的FastJson (https://github.com/alibaba/fastjon)
  3. Google 的GSON (https://github.com/google/gson)
  这几种json序列化工具中,Jackson 与fastjson 要比GSON 的性能要好,可是Jackson、GSON 的稳定性要比Fastjson 好。而fastjson的优点在于提供的api 很是容易使用。

  用阿里的FastJson来示例一下:

public class FastjsonSerializeer implements ISerializer { @Override public <T> byte[] serializer(T obj) { return JSON.toJSONBytes(obj); } @Override public <T> T deSerializer(byte[] bytes, Class<T> clazz) { return (T)JSON.parseObject(bytes,clazz); } public static void main(String[] args) { ISerializer iSerializer = new FastjsonSerializeer(); User user = new User(); byte [] bytes = iSerializer.serializer(user); user.setName("jolivan"); System.out.println(new String(bytes)); User userNow = iSerializer.deSerializer(bytes,User.class); System.out.println(userNow.getName()); } }

===================输出=====================

{"age":"23","name":"Lushe"}
Lushe

 

hessian

  dubbo里使用的就是它,但对它作了优化,又称为hessian2。

Protobuf

  优点:(1)独立语言(能够基于不一样的语言)、独立平台(跨平台交互)(2)性能高,压缩性好;(3)解析性好

  缺陷:实现起来很麻烦,学习成本大。

  它有独立的编译器

序列化的实际应用举例

  好比说咱们在一个分布式系统中,有一个订单模块和一个支付模块,订单模块基于一个协议(dubbo)调用订单系统,底层传输的事二进制数据,那么咱们要作的事情就是把对象转化为一个二进制数据,这就是序列化的场景。

相关文章
相关标签/搜索