1、概述
Java 提供了一种对象序列化的机制,该机制中,一个对象可以被表示为一个字节序列,该字节序列包括该对象的数据、有关对象的类型的信息和存储在对象中数据的类型。
将序列化对象写入文件之后,可以从文件中读取出来,并且对它进行反序列化,也就是说,对象的类型信息、对象的数据,还有对象中的数据类型可以用来在内存中新建对象。
整个过程都是 Java 虚拟机(JVM)独立的,也就是说,在一个平台上序列化的对象可以在另一个完全不同的平台上反序列化该对象。
使用场景:所有可在网络上传输的对象都必须是可序列化的,比如RMI(remote method invoke
,即远程方法调用,传入的参数或返回的对象都是可序列化的,否则会出错;所有需要保存到磁盘的java对象都必须是可序列化的。通常建议:程序创建的每个JavaBean类都实现Serializeable接口。
2、实现
类ObjectInputStream 和 ObjectOutputStream 是高层次的数据流,它们包含反序列化和序列化对象的方法。
- ObjectOutputStream 类包含的
writeObject()
序列化一个对象,并将它发送到输出流:public final void writeObject(Object x) throws IOException
- 相似的`ObjectInputStream 类包含如下反序列化一个对象的方法:
public final Object readObject() throws IOExceptio
1、类
class Person implements Serializable {
private String name;
private int age;
private transient int tele;
public Person(String name, int age ,int tele) {
this.name = name;
this.age = age;
this.tele= tele;
}
public String toString() {
return "Person:" + "name='" + name + '\'' + ", age=" + age + '\'' + ", tele=" + tele;
}
}
一个类的对象要想序列化成功,必须满足两个条件:
-
该类必须实现
java.io.Serializable
接口; -
该类的所有属性必须是可序列化的。如果有一个属性不是可序列化的,则该属性必须注明是短暂的(
transient
)。
如果你想知道一个 Java 标准类是否是可序列化的,请查看该类的文档。检验一个类的实例是否能序列化十分简单, 只需要查看该类有没有实现 java.io.Serializable
接口
2、序列化对象
public class SerializeDemo{
public static void main(String[] args) {
Person person = new Person("Jeffrey", 18, 110);
try {
//首先创建一个指定的对象,表示文件中的写入数据的文件输出流
FileOutputStream fileOut = new FileOutputStream("Person.ser");
///创建一个ObjectOutputStream输出流
ObjectOutputStream out = new ObjectOutputStream(fileOut);
out.writeObject(person);
out.close();
fileOut.close();
System.out.printf("Serialized data is saved in Person.ser");
} catch (IOException e) {
e.printStackTrace();
}
}
}
3、反序列化对象
public class DeserializeDemo{
public static void main(String[] args) {
try {
//首先创建一个指定的对象,表示文件中的写入数据的文件输出流
FileInputStream filein = new FileInputStream("Person.ser");
///创建一个ObjectOutputStream输出流
ObjectInputStream in = new ObjectInputStream(filein);
Person person = (Person)in.readObject();
in.close();
filein.close();
System.out.printf(person.toString());
} catch (IOException i) {
i.printStackTrace();
}
catch (ClassNotFoundException c){
System.out.println("Employee class not found");
c.printStackTrace();
}
}
}
打印结果:
Person:name='Jeffrey', age=18', tele=0
readObject()
方法中的try/catch
代码块尝试捕获 ClassNotFoundException 异常。对于 JVM 可以反序列化对象,它必须是能够找到字节码的类。如果JVM在反序列化对象的过程中找不到该类,则抛出一个 ClassNotFoundException 异常。- 当对象被序列化时,属性
tele
的值为 110,但是因为该属性是短暂的,该值没有被发送到输出流。所以反序列化后 Person 对象的tele
属性为 0。
4、serialVersionUID
一般来说,定义serialVersionUID的方式有两种,分别为:
-
采用默认的1L,具体为private static final long serialVersionUID = 1L;
-
根据类名、接口名、成员方法及属性等来生成一个64位的哈希字段,例如 private static final long serialVersionUID = XXXL;
doc文档概述:serialVersionUID 是 Java 为每个序列化类产生的版本标识,可用来保证在反序列时,发送方发送的和接受方接收的是可兼容的对象。如果接收方接收的类的 serialVersionUID 与发送方发送的 serialVersionUID 不一致,进行反序列时会抛出 InvalidClassException。
详细内容阅读为什么阿里巴巴要求程序员谨慎修改serialVersionUID 字段的值
参考菜鸟的Java 序列化。