Java中的序列化和反序列化示例
序列化是一种将对象的状态转换为字节流的机制。反序列化是使用字节流在内存中重新创建实际Java对象的逆过程。该机制用于持久化对象。
创建的字节流与平台无关。因此,在一个平台上序列化的对象可以在不同平台上反序列化。
为了使Java对象可序列化,我们实现了Java.io.Serializable接口。
ObjectOutputStream 类包含用于序列化对象的writeObject()方法。
public final void writeObject(Object obj)
throws IOException
ObjectInputStream 类包含用于反序列化对象的readObject()方法。
public final Object readObject()
throws IOException,
ClassNotFoundException
序列化的优点
1. 保存/保持对象的状态。
2. 在网络上移动一个物体。
只有那些实现Java.io.Serializable接口的类的对象才能被序列化。
Serializable 是一个标记接口(没有数据成员和方法)。它用于“标记” Java类,以便这些类的对象可以获得一定的能力。标记接口的其他示例是:- 可克隆和远程。
要记住的要点
1.如果父类实现了Serializable接口,则子类不需要实现,反之则不然。
2. 通过序列化过程只保存非静态数据成员。
3. 静态数据成员和瞬态数据成员不通过序列化过程保存。因此,如果您不想保存非静态数据成员的值,请使其成为瞬态。
4. 反序列化对象时从不调用对象的构造函数。
5.关联对象必须实现Serializable接口。
例子 :
class A implements Serializable{
// B also implements Serializable
// interface.
B ob=new B();
}
SerialVersionUID
序列化运行时将版本号与称为 SerialVersionUID 的每个可序列化类相关联,在反序列化期间使用该版本号来验证序列化对象的发送方和接收方是否已为该对象加载了与序列化兼容的类。如果接收者为对象加载了一个类,该对象的 UID 与相应发送者的类的 UID 不同,则反序列化将导致InvalidClassException 。 Serializable 类可以通过声明字段名称来显式声明自己的 UID。
它必须是静态的、最终的和长类型的。
即- ANY-ACCESS-MODIFIER static final long serialVersionUID=42L;
如果可序列化类没有显式声明 serialVersionUID,则序列化运行时将根据类的各个方面为该类计算默认值,如Java对象序列化规范中所述。但是强烈建议所有可序列化的类都显式声明 serialVersionUID 值,因为它的计算对类细节高度敏感,这些细节可能因编译器实现而异,类的任何更改或使用不同的 id 都可能影响序列化数据。
还建议对 UID 使用 private 修饰符,因为它不能用作继承的成员。
串行器
serialver 是 JDK 自带的工具。它用于获取Java类的 serialVersionUID 编号。
您可以运行以下命令来获取 serialVersionUID
serialver [-classpath 类路径] [-show] [类名...]
示例 1:
// Java code for serialization and deserialization
// of a Java object
import java.io.*;
class Demo implements java.io.Serializable
{
public int a;
public String b;
// Default constructor
public Demo(int a, String b)
{
this.a = a;
this.b = b;
}
}
class Test
{
public static void main(String[] args)
{
Demo object = new Demo(1, "geeksforgeeks");
String filename = "file.ser";
// Serialization
try
{
//Saving of object in a file
FileOutputStream file = new FileOutputStream(filename);
ObjectOutputStream out = new ObjectOutputStream(file);
// Method for serialization of object
out.writeObject(object);
out.close();
file.close();
System.out.println("Object has been serialized");
}
catch(IOException ex)
{
System.out.println("IOException is caught");
}
Demo object1 = null;
// Deserialization
try
{
// Reading the object from a file
FileInputStream file = new FileInputStream(filename);
ObjectInputStream in = new ObjectInputStream(file);
// Method for deserialization of object
object1 = (Demo)in.readObject();
in.close();
file.close();
System.out.println("Object has been deserialized ");
System.out.println("a = " + object1.a);
System.out.println("b = " + object1.b);
}
catch(IOException ex)
{
System.out.println("IOException is caught");
}
catch(ClassNotFoundException ex)
{
System.out.println("ClassNotFoundException is caught");
}
}
}
输出 :
Object has been serialized
Object has been deserialized
a = 1
b = geeksforgeeks
示例 2:
// Java code for serialization and deserialization
// of a Java object
import java.io.*;
class Emp implements Serializable {
private static final long serialversionUID =
129348938L;
transient int a;
static int b;
String name;
int age;
// Default constructor
public Emp(String name, int age, int a, int b)
{
this.name = name;
this.age = age;
this.a = a;
this.b = b;
}
}
public class SerialExample {
public static void printdata(Emp object1)
{
System.out.println("name = " + object1.name);
System.out.println("age = " + object1.age);
System.out.println("a = " + object1.a);
System.out.println("b = " + object1.b);
}
public static void main(String[] args)
{
Emp object = new Emp("ab", 20, 2, 1000);
String filename = "shubham.txt";
// Serialization
try {
// Saving of object in a file
FileOutputStream file = new FileOutputStream
(filename);
ObjectOutputStream out = new ObjectOutputStream
(file);
// Method for serialization of object
out.writeObject(object);
out.close();
file.close();
System.out.println("Object has been serialized\n"
+ "Data before Deserialization.");
printdata(object);
// value of static variable changed
object.b = 2000;
}
catch (IOException ex) {
System.out.println("IOException is caught");
}
object = null;
// Deserialization
try {
// Reading the object from a file
FileInputStream file = new FileInputStream
(filename);
ObjectInputStream in = new ObjectInputStream
(file);
// Method for deserialization of object
object = (Emp)in.readObject();
in.close();
file.close();
System.out.println("Object has been deserialized\n"
+ "Data after Deserialization.");
printdata(object);
// System.out.println("z = " + object1.z);
}
catch (IOException ex) {
System.out.println("IOException is caught");
}
catch (ClassNotFoundException ex) {
System.out.println("ClassNotFoundException" +
" is caught");
}
}
}
输出:
Object has been serialized
Data before Deserialization.
name = ab
age = 20
a = 2
b = 1000
Object has been deserialized
Data after Deserialization.
name = ab
age = 20
a = 0
b = 2000
输出说明:
您在反序列化对象时已经看到 a 和 b 的值发生了变化。原因是 a 被标记为瞬态而 b 是静态的。
对于瞬态变量:-使用瞬态关键字定义的变量在序列化过程中不会序列化。该变量将在反序列化过程中使用默认值初始化。 (例如:对于对象,它是 null,对于 int,它是 0)。
在静态变量的情况下:-用 static 关键字定义的变量在序列化过程中不会序列化。这个变量将在反序列化过程中加载类中定义的当前值。