概念:java
Java 提供了一种对象序列化的机制,一个对象能够被表示为一个字节序列,该字节序列包括该对象的数据、有关对象的类型的信息和存储在对象中数据的类型。将序列化对象写入文件以后,能够从文件中读取出来,而且对它进行反序列化。也就是说,对象的类型信息、对象的数据,还有对象中的数据类型能够用来在内存中新建对象。数组
整个过程都是 Java 虚拟机(JVM)独立的,也就是说,在一个平台上序列化的对象能够在另外一个彻底不一样的平台上反序列化该对象。网络
实现:ide
一个类实现了Serializable接口,它就能够被序列化工具
public class Employee implements java.io.Serializablespa
若是被写对象的类型是String,或数组,或Enum,或Serializable,那么就能够对该对象进行序列化,不然将抛出NotSerializableException对象
JDK中的序列化API:继承
java.io.ObjectOutputStream表明对象输出流,它的writeObject(Object obj)方法可对参数指定的obj对象进行序列化,把获得的字节序列写到目标输出流中。接口
java.io.ObjectInputStream表明对象输入流,它的readObject()方法从一个源输入流中读取字节序列,再把它们反序列化为一个对象,并将其返回。ip
只有实现了Serializable和Externalizable接口的类的对象才能被序列化。Externalizable接口继承自 Serializable接口,实现Externalizable接口的类彻底由自身来控制序列化的行为,而仅实现Serializable接口的类能够采用默认的序列化方式 。
对象序列化包括以下步骤:
1)建立一个对象输出流,它能够包装一个其余类型的目标输出流,如文件输出流;
2)经过对象输出流的writeObject()方法写对象。
对象反序列化的步骤以下:
1)建立一个对象输入流,它能够包装一个其余类型的源输入流,如文件输入流;
2)经过对象输入流的readObject()方法读取对象。
特殊状况:
对于一个实体类,不想将全部的属性都进行序列化,有专门的关键字 transient:
private transient int name;
对该类序列化时会自动忽略被 transient 修饰的属性,反序列化后name=0。
更多:
1.序列化ID:
凡是实现Serializable接口的类都有一个表示序列化版本标识符的静态变量
private static final long serialVersionUID = 1L
情境:两个客户端 A 和 B 试图经过网络传递对象数据,A 端将对象序列化为二进制数据再传给 B,B 反序列化获得对象。
问题:反序列化时老是提示不成功。
解决:虚拟机是否容许反序列化,不只取决于类路径和功能代码是否一致,还有两个类的序列化 ID 是否一致。
序列化 ID 在 Eclipse 下提供了两种生成策略,一个是固定的 1L,一个是随机生成一个不重复的 long 类型数据(其实是使用 JDK 工具生成)。随机生成的序列化 ID 有什么做用呢,有些时候,经过改变序列化 ID 能够用来限制某些用户的使用。
2.不保存静态变量
public class Test implements Serializable{
public static int staticVar = 5;
}
//序列化,写入路径result.obj
ObjectOutputStream out = new ObjectOutputStream(
new FileOutputStream("result.obj"));
out.writeObject(new Test());
out.close();
//序列化后修改成10
Test.staticVar = 10;
//反序列化,读取
ObjectInputStream oin = new ObjectInputStream(new FileInputStream("result.obj"));
Test t = (Test) oin.readObject();
oin.close();
System.out.println(t.staticVar); //结果是10
序列化保存对象的状态,静态变量属于类的状态,所以序列化并不保存静态变量。