序列化与反序列化

1. 什么是序列化?

  1. java序列化是指把java对象转换为字节序列的过程,而java反序列化是指把字节序列恢复为java对象的过程
  2. 序列化:对象序列化的最主要的用处就是在传递和保存对象的时候,保证对象的完整性和可传递性。序列化是把对象转换成有序字节流,以便在网络上传输或者保存在本地文件中。序列化后的字节流保存的java对象的状态以及相关的描述信息。序列化机制的核心作用就是对象状态的保存与重建。
  3. 反序列化:客户端从文件中或网络上获得序列化后的对象字节流后,根据字节流中所保存的对象状态及描述信息,通过反序列化重建对象。
  4. 序列化就是把实体对象状态按照一定的格式写入到有序字节流,反序列化就是从有序字节流重建对象,恢复对象状态

2. 为什么需要序列化与反序列化

当两个进程进行远程通信时,可以相互发送各种类型的数据,包括文本,图片,音频,视频等,而这些数据都会以二进制的形式在网络上传送。
当两个java进行进行通信时,要传送对象,怎么传对象,通过序列化与反序列化。
也就是说,发送方需要把对象转换为字节序列,然后在网络上传送,另一方面,接收方需要从字节序列中恢复出java对象

3. 序列化的好处

  1. 永久性保存对象,保存对象的字节序列到本地文件或者数据库中,实现了数据的持久化,通过序列化可以把数据永久的保存到硬盘上,
  2. 利用序列化实现远程通信,可以在网络上传送对象的字节序列。
  3. 在进程间传递对象

4. Java 如何实现序列化和反序列化

4.1.JDK类库中序列化API

java.io.ObjectOutputStream: 表示输出对象流,它的writeObject(Object obj)方法可以对参数指定的obj对象进行序列化,把得到的字节序列写到一个目标输出流中;
java.io.ObjectInputStream:表示对象输入流,它的readObject()方法源输入流中读取字节序列,再把它们反序列化成为一个对象,并将其返回.

4.2 实现序列化的要求

只有实现了Serializable或Externalizable接口的对象才能被序列化,否则抛出异常!

4.3 实现java对象序列化与反序列化的方法

例 a 类,它的对象需要序列化,有3种方法

如果类a仅仅实现了Serializable接口,则ObjectOutputStream采用默认的序列化方式,对a对象的非transient实例变量进行序列化,ObjectInputStream采用默认的反序列化方式,对a对象的非transient实例变量进行反序列化

如果类a仅仅实现了Serializable接口,并且还定义了a对象的writeObject(ObjectOutputStream out) 和readObject(ObjectInputStream in),则ObjectOutputStream调用a对象的writeObject(ObjectOutputStream out)的方法进行序列化,ObjectInputStream调用a对象的readObject(ObjectInputStream in)的方法进行序列化

如果a类实现了ExternaInalizable接口,且User类必须实现readExternam(ObjectInput in)和wiriteExternal(ObjectOutput out)方法,则
ObjectOutputStream调用a对象的wiriteExternal(ObjectOutput out)的方法进行序列化,ObjectInputStream调用a对象的readExternam(ObjectInput in)的方法进行序列化‘’

使用]DK类库中序列化的步骤

  1. 创建一个对象输出流,它可以包装一个奇特类型的目标输出流,如文件输出流:
    objectOutputStream oos=new objectOutputStream(new FileOutStream(c:\object.out));

  2. 通过对象输出流writeObject()方法写对象:
    oos.writeObject(new a(“hehe”,“123456”,“male”));

JDK类库中反序列化的步骤

  1. 创建一个对象输入流,它可以包装一个其他类型输入流,如文件输入流:
    objectInputStream ois=new ObjectInputStream(new FileInputStream(“object.out”));
  2. 通过对象输出流的readObject()方法读取对象:
    a aa=(a)ois.readObject();
  3. 为了正确读数据,完成反序列化,必须保证向对象输出流写对象的顺序与从对象输入流中读对象的顺序一致

简单例子

import java.awt.print.Printable;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
 
 
public class SerialDemo {
       public static void main(String[] args) throws IOException,ClassNotFoundException{
               
              FileOutputStream fos =new FileOutputStream("object.out");
              ObjectOutputStream oos=new ObjectOutputStream(fos);
              User user1=new User("hehe","123456","male");
              oos.writeObject(user1);
              System.out.print(oos);
              oos.flush();
              oos.close();
               
              FileInputStream fis=new FileInputStream("object.out");
              ObjectInputStream ois=new ObjectInputStream(fis);
              User user2=(User) ois.readObject();
              System.out.print(user2.getUserName()+" "+ user2.getPassword()+" " + user2.getSex());
       }
}
 
 
 
import java.io.Serializable;
 
public class User implements Serializable {
       public User(String string, String string2, String string3) {
              // TODO Auto-generated constructor stub
       }
       private String userName;
       private String password;
       private String sex;
        
       public String getUserName() {
              return userName;
       }
       public String getPassword() {
              return password;
       }
       public String getSex() {
              return sex;
       }
}

5.serialVersionUID 这个的值到底是在怎么设置的,有什么用?

序列化运行时使用一个称为 serialVersionUID 的版本号与每个可序列化类相关联,该序列号在反序列化过程中用于验证序列化对象的发送者和接收者是否为该对象加载了与序列化兼容的类。如果接收者加载的该对象的类的 serialVersionUID 与对应的发送者的类的版本号不同,则反序列化将会导致 InvalidClassException。可序列化类可以通过声明名为 “serialVersionUID” 的字段(该字段必须是静态 (static)、最终 (final) 的 long 型字段)显式声明其自己的 serialVersionUID:

如果可序列化类未显式声明 serialVersionUID,则序列化运行时将基于该类的各个方面计算该类的默认 serialVersionUID 值,如“Java™ 对象序列化规范”中所述。不过,强烈建议 所有可序列化类都显式声明serialVersionUID 值,原因是计算默认的 serialVersionUID 对类的详细信息具有较高的敏感性,根据编译器实现的不同可能千差万别,这样在反序列化过程中可能会导致意外的 InvalidClassException。因此,为保证 serialVersionUID 值跨不同 java 编译器实现的一致性,序列化类必须声明一个明确的 serialVersionUID 值。还强烈建议使用 private 修饰符显示声明 serialVersionUID(如果可能),原因是这种声明仅应用于直接声明类 – serialVersionUID 字段作为继承成员没有用处。数组类不能声明一个明确的 serialVersionUID,因此它们总是具有默认的计算值,但是数组类没有匹配 serialVersionUID 值的要求。

6. 是否一定要实现Serializable接口序列化

通过实现Serializable接口的方式去进行序列化操作,在性能上来讲并不是最佳选择。那么,在性能考虑的情况下,很多人都会选择其他更为高效率的产品替代serializable接口.第三方框架性能分析----》直通车

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值