java.io.Serializable(序列化)接口详细总结

一、前言

  本篇是我刚参加工作时写的总结,是一篇不错的科普文,若想更深一步的了解序列化相关的知识,欢迎阅读另一篇博文:序列化的魔力。
  工作后做的第一个项目是电商项目。当时不会做项目,只能照猫画虎。其中一个VO类为何要实现Serializable接口一直没有理解,不实现这个Serializable,会报错。如下是随手写的一个VO类Person.java:

import java.io.Serializable;
public class Person implements Serializable {
	private static final long serialVersionUID = 1L;
	//两个属性及getter、setter方法
	private String name;
	private String age;

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public String getAge() {
		return age;
	}

	public void setAge(String age) {
		this.age = age;
	}
}

二、什么是序列化、反序列化

  翻阅JDK1.8的官方开发文档,发现Serializable接口没有方法和字段,仅用于标识可序列化的VO类。不实现此接口的类的任何字段(属性)都不能序列化和反序列化。那么什么是序列化和反序列化呢?

  由于序列化和反序列化概念太抽象,还是通过两个场景来理解为上策。

  (场景一)以上面提到的Person.java为例。这个VO类中的两个字段name和age在程序运行后都在堆内存中,程序执行完毕后内存得到释放,name和age的值也不复存在。如果现在计算机要把这个类的实例发送到另一台机器、或是想保存这个VO类的实例到数据库(持久化对象),以便以后再取出来用。这时就需要对这个类进行序列化,便于传送或保存。用的时候再反序列化重新生成这个对象的实例。

  (场景二)以搬桌子为例,桌子太大了不能通过比较小的门,我们要把它拆了再运进去,这个拆桌子的过程就是序列化。同理,反序列化就是等我们需要用桌子的时候再把它组合起来,这个过程就是反序列化。

  学到这里就可以给**“序列化”下一个定义了**:
  把原本在内存中的对象状态 变成可存储或传输的过程称之为序列化。序列化之后,就可以把序列化后的内容写入磁盘,或者通过网络传输到别的机器上。

  序列化前的对象和反序列化后得到的对象,内容是一样的(且对象中包含的引用也相同),但两个对象的地址不同。换句话说,序列化操作可以实现对任何可Serializable对象的”深度复制(deep copy)"。

三、什么情况下需要序列化

通过上面的分析,我们不难看出,一下三种情况需要使用序列化接口:

a)当你想把的内存中的对象状态保存到一个文件中或者数据库中,以便可以在以后重新创建精确的副本;
b)当你想用套接字在网络上传送对象的时候(从一个应用程序域发送到另一个应用程序域中);
c)当你想通过RMI传输对象的时候;

四、注意事项:

a)序列化时,只对对象的状态进行保存,而不管对象的方法;
b)当一个父类实现序列化,子类自动实现序列化,不需要显式实现Serializable接口;
c)当一个对象的实例变量引用其他对象,序列化该对象时也把引用对象进行序列化;
d)并非所有的对象都可以序列化。
e) 序列化会忽略静态变量,即序列化不保存静态变量的状态。静态成员属于类级别的,不能序列化。添加了static、transient关键字后的变量不能序列化。

五、序列化ID

private static final long serialVersionUID = 1L;

  序列化 ID在 Eclipse 下提供了两种生成策略,一个设为固定的 1L,另一个是随机生成一个不重复的 long 类型数据(实际上是使用 JDK 工具生成)。一般如果没有特殊需求,用默认的 1L 就可以,这样可以确保反序列化成功。因为不同的序列化id之间不能进行序列化和反序列化。

你可能感兴趣的:(JAVA提高)