8.11 Java 序列化 与 反序列化
什么是序列化?
Java序列化是一种将对象转换为字节流的过程,以便在网络上传输或在文件中存储对象。
序列化可以将对象的状态保存到磁盘或通过网络传输,
然后可以通过反序列化重新创建对象,
使得对象的状态能够在不同的环境中进行传递和存储。
do shi te 要用序列化?
- 网络传输:通过序列化,可以将对象转换为字节流,在网络上传输。在客户端和服务器之间传递对象数据时,可以将对象序列化为字节流,通过网络传输,在接收端进行反序列化还原为对象。
- 持久化存储:通过序列化,可以将对象保存到文件或数据库中,实现对对象的持久化存储。在需要保存对象状态的时候,将对象序列化到存储介质中,可以实现数据的长期保存和读取。
- 跨平台通信:Java序列化是一种平台无关的机制,可以将对象序列化为字节流后,在不同的平台上进行传输和传递。这意味着使用Java序列化,可以在不同的操作系统和编程语言之间实现对象的交互通信。
序列化是Java跨平台强大的很大一个部分原因!!!
Java的跨平台性是由多个因素共同作用而实现的,其中序列化确实是其中一个重要的方面之一,但并不是全部。以下是一些影响Java跨平台性的因素:
字节码:Java编译器将Java源代码编译为字节码,而不是针对特定的硬件或操作系统生成机器码。这种字节码的特性使得Java程序能够在不同的平台上运行。
JVM(Java虚拟机):Java字节码通过JVM来执行。JVM是针对特定平台的软件,负责将字节码解释或编译为特定平台的机器码。通过JVM的存在,Java程序能够在不同的操作系统和硬件平台上运行。
标准库:Java标准库提供了丰富的跨平台API,使得开发者能够编写与平台无关的代码。Java标准库提供了跨平台的网络、IO、图形界面等功能,使得开发者能够以相似的方式操作不同的底层平台。
序列化:作为Java的重要特性之一,序列化确实提供了一种跨平台的对象交换方式。通过序列化,可以将对象转换为字节流进行传输或存储,使得对象的状态能够在不同的环境中传递和存储。这为数据的跨平台传输和存储提供了方便。
要序列化的前提条件:
实现 java.io.Serializable接口
public class Employee implements java.io.Serializable
{
public String name;
public String address;
public transient int SSN;
public int number;
public void mailCheck()
{
System.out.println("Mailing a check to " + name
+ " " + address);
}
}
序列化
请注意,一个类的对象要想序列化成功,必须满足两个条件:
该类必须实现 java.io.Serializable 接口。
该类的所有属性必须是可序列化的。如果有一个属性不是可序列化的,则该属性必须注明是短暂的。
如果你想知道一个 Java 标准类是否是可序列化的,请查看该类的文档。检验一个类的实例是否能序列化十分简单, 只需要查看该类有没有实现 java.io.Serializable接口。
import java.io.*;
public class Mine{
public static void main(String [] args)
{
Employee e = new Employee();
e.name = "Kasaki Nozomi";
e.address = "Japan, Kitauji";
e.SSN = 11122333;
e.number = 1203;
try
{
FileOutputStream fileOut =
new FileOutputStream("employee.ser");
ObjectOutputStream out = new ObjectOutputStream(fileOut);
out.writeObject(e);
out.close();
fileOut.close();
System.out.printf("Serialized data is saved in /tmp/employee.ser");
}catch(IOException i)
{
i.printStackTrace();
}
}
}
反序列化
import java.io.*;
public class Deserialized {
static <T> void pln(T x) {
System.out.println(x);
}
public static void main(String[] args) {
Employee e = null;
try {
FileInputStream fileIn = new FileInputStream("employee.ser");
ObjectInputStream in = new ObjectInputStream(fileIn);
e = (Employee) in.readObject();
in.close();
fileIn.close();
} catch (IOException e1) {
e1.printStackTrace();
return;
}catch (ClassNotFoundException e2) {
System.out.printf("[%s] class not found.",e.getClass());
e2.printStackTrace();
return;
}
pln("Deserialized Employee...");
pln("Name: " + e.name);
pln("Address: " + e.address);
}
}
关于 transient:
- 序列化的时候 用transient修饰的数据(密码等隐私数据) 不会被JVM序列化
- 线程不安全变量: 当一个成员变量在多线程环境下被访问并修改时,为了保证线程安全,可以将该成员变量声明为 transient,这样每个线程都将使用自己的本地副本,避免了对数据的冲突访问。
- 内存缓存:有时候,我们会使用缓存来提高程序的性能,但是缓存通常不需要被持久化,可以将缓存字段声明为 transient,这样在对象持久化的过程中不会保存缓存的内容。
- 非序列化框架:有些第三方框架在进行对象序列化时会自动忽略 transient 字段,例如 Jackson、Gson 等。如果你希望某些字段在使用这些框架进行序列化时被忽略,可以将它们声明为 transient。
不得不说GPT对学习真的有极大的帮助!大部分都不用在网上找无用信息了