序列化与反序列化的进一步理解.md

个人觉得Java基础是一个学习时间线很长的事情,所以这里进行总结,温故知新吧

序列化在学习Java基础的时候都会接触,众所周知,他就是将对象的状态保存为字节序列的形式,这样就可以进行文件形式的存储与网络传输,可以保证对象的完整性和可传递性,但是接下来的总结还包括序列化与反序列化是如何实现的?

1.序列化与反序列化的好处

好处一就是实现了数据的持久化,内存中的对象可以保存到硬盘上的文件中,通常是一个class文件,我们都知道内存是掉电会丢失数据,通过持久化可以解决问题。

好处二就是利用序列化可以实现远程通信,我们知道不同主机上的两个进程可以通过Socket的方式进行通信,相关内容会以二进制字节流的方式进行传递,那么两个Java进行之间是通过序列化的方式进行对象的传递,在网络上传递对象的字节序列。

2.Java如何实现序列化与反序列化

1、JDK类库中序列化和反序列化API

(1)java.io.ObjectOutputStream:表示对象输出流;

它的writeObject(Object obj)方法可以对参数指定的obj对象进行序列化,把得到的字节序列写到一个目标输出流中;

(2)java.io.ObjectInputStream:表示对象输入流;

它的readObject()方法源输入流中读取字节序列,再把它们反序列化成为一个对象,并将其返回;

2、实现序列化的要求

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

3、实现Java对象序列化与反序列化的方法

假定一个User类,它的对象需要序列化,可以有如下三种方法:

(1)若User类仅仅实现了Serializable接口,则可以按照以下方式进行序列化和反序列化

ObjectOutputStream采用默认的序列化方式,对User对象的非transient的实例变量进行序列化。
ObjcetInputStream采用默认的反序列化方式,对对User对象的非transient的实例变量进行反序列化。

(2)若User类仅仅实现了Serializable接口,并且还定义了readObject(ObjectInputStream in)和writeObject(ObjectOutputSteam out),则采用以下方式进行序列化与反序列化。

ObjectOutputStream调用User对象的writeObject(ObjectOutputStream out)的方法进行序列化。
ObjectInputStream会调用User对象的readObject(ObjectInputStream in)的方法进行反序列化。

(3)若User类实现了Externalnalizable接口,且User类必须实现readExternal(ObjectInput in)和writeExternal(ObjectOutput out)方法,则按照以下方式进行序列化与反序列化。

ObjectOutputStream调用User对象的writeExternal(ObjectOutput out))的方法进行序列化。
ObjectInputStream会调用User对象的readExternal(ObjectInput in)的方法进行反序列化。

4、JDK类库中序列化的步骤

步骤一:创建一个对象输出流,它可以包装一个其它类型的目标输出流,如文件输出流:

ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("D:\object.out"));

步骤二:通过对象输出流的writeObject()方法写对象:

oos.writeObject(new User("xuliugen", "123456", "male"));
5、JDK类库中反序列化的步骤

步骤一:创建一个对象输入流,它可以包装一个其它类型输入流,如文件输入流:

ObjectInputStream ois= new ObjectInputStream(new FileInputStream("object.out"));
步骤二:通过对象输出流的readObject()方法读取对象:

User user = (User) ois.readObject();
说明:为了正确读取数据,完成反序列化,必须保证向对象输出流写对象的顺序与从对象输入流中读对象的顺序一致。

3.相关细节

  1. 序列化时只保存对象的状态,不保存其方法

  2. 如果一个父类实现序列化,那么子类自动实现序列化,不需要显式实现Seralizable接口

  3. 如果一个对象实例中引入了其他对象,那么序列化这个对象的时候,将引用对象也进行实例化

  4. 并非所有的对象都可以序列化,至于为什么不可以,有很多原因了,比如:

    安全方面的原因,比如一个对象拥有private,public等field,对于一个要传输的对象,比如写到文件,或者进行RMI传输等等,在序列化进行传输的过程中,这个对象的private等域是不受保护的;

    资源分配方面的原因,比如socket,thread类,如果可以序列化,进行传输或者保存,也无法对他们进行重新的资源分配,而且,也是没有必要这样实现;

  5. 声明为static和transient类型的成员变量不能被序列化,static表示类的状态,transient表示临时变量

  6. 个人理解:序列化与反序列化的过程,就是生成和解析class文件的过程。

参考文章:

https://blog.csdn.net/xlgen157387/article/details/79840134