1.为什么需要 Java 序列化(Serialization)?
Java 提供了一种对象序列化和反序列化的机制。 序列化就是一种用来处理对象流的机制,所谓对象流也就是将对象的内容进行流化。
序列化的流叫做序列化流(持久化对象);反序列化的流叫做反序列化流(重构对象)。
可以对流化后的对象进行 读 写 操作,也可将流化后的对象传输于网络之间。
简而言之,对象序列化是将对象状态转换为可保持或传输的格式过程。
序列化是为了解决在对对象流进行读写操作时所引发的问题。
2.如何实现 Java 序列化(Serialization)?
将 需 要 被 序 列 化 的 类 实 现 Serializable 接 口 , 该 接 口 没 有 需 要 实 现 的 方 法 , implements Serializable 只是为了标注该对象是可被序列化的,然后使用一个输出流(如:FileOutputStream)来构造 一个 ObjectOutputStream(对象流)对象,接着,使用 ObjectOutputStream 对象的 writeObject(Object obj)方法就 可以将参数为 obj 的对象写出(即保存其状态),要恢复的话则用输入流。
3.Java 序列化中,如果有些字段不想进行序列化怎么办?
对于不想进行序列化的变量,使用 transient 关键字修饰。
当对象被序列化时,阻止实例中那些用此关键字修饰的的变量序列化。
当对象被反序列化时,被 transient 修饰的变量值不会被持久化和恢复。
transient 只能修饰变量,不能修饰类和方法。
4.序列化 和 反序列化 作用
序列化:主要用于网络传输,数据持久化,一般序列化也称为编码(Encode)。
反序列化:主要用于从网络或磁盘上读取字节数组还原成原始对象,一般反序列化也称为解码(Decode)。
序列化 和 反序列化作用:
1.数据持久化:简而言之,就是将数据存储到磁盘文件的时候,需要将对象序列化存入磁盘中。
2.网络传输中:当分布式系统中需要传输同一个对象时,就用到序列化与反序列化。将传输的对象序列化传输到另一个系统中,另一个系统读取的时候通过将字节序列转换为对象读取出来
序列化,是指把Java对象转换为字节序列的过程(持久化对象)
java.io.ObjectOutputStream类继承OutputStream,
是一个字节输出流,可以用来写出字节数据,并且可以写对象。
序列化的注意事项:
1被序列化的对象所属的类一定要实现Serializable接口(标记接口)
2被序列化的对象所有的属性也是要可以被序列化的
3如果别的序列化的对象的属性不想被序列化,那么该属性就需要使用transient关键字修饰,表示瞬态
public class Person implements Serializable {
static final long serialVersionUID=21L;//序列化版本号
String name;
int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
//序列化
public class Test01 {
public static void main(String[] args) throws Exception{
// 1.创建Person对象
Person p = new Person("张三",18);
// 2.创建序列化流对象,关联目的地文件路径
FileOutputStream fos = new FileOutputStream("day01\\aa\\a.txt");
ObjectOutputStream oos = new ObjectOutputStream(fos);
// 3.序列化对象
oos.writeObject(p);
// 4.关闭流,释放资源
oos.close();
}
}
反序列化,是指把字节序列恢复为Java对象的过程(重建对象)
java.io.ObjectInputStream类继承InputStream,
是一个字节输入流,可以用来读字节数据,并且可以读对象。
反序列化的注意事项:
1如果找不到class文件,反序列化会失败,抛出一个classNotFoundException异常incompatible
2.如果能找到该类的class文件,但序列化后又修改了类,会导致反序列化失败,抛出一个InvalidClassException异常
解决InvalidClassException异常的反序列化方法:增加序列化版本号:static final long serialVersionUID=21L
//反序列化
public class Test02 {
public static void main(String[] args) throws Exception{
// 1.创建反序列化流对象,关联数据源文件路径
FileInputStream fis = new FileInputStream("day01\\aa\\a.txt");
ObjectInputStream ois = new ObjectInputStream(fis);
// 2.重构对象
Object obj = ois.readObject();
// 3.关闭流,释放资源
ois.close();
// 4.打印对象
System.out.println(obj.toString());
}
}
序列化和反序列化注意:
声明为static和transient类型的数据不能被序列化,反序列化需要一个无参构造函数。
在 Java 中能够被序列化的类必须先实现 Serializable 接口,该接口没有任何抽象方法只是起到一个标记作用。
Json/xml的数据传递:
在数据传输(也称为网络传输)前,先通过序列化工具类将Java对象序列化为Json/xml文件。
在数据传输(也称为网络传输)后,再将Json/xml文件反序列化为对应语言的对象。
序列化版本号(serialVersionUID)
serialVersionUID: 字面意思上是序列化的版本号,凡是实现Serializable接口的类都有一个表示序列化版本标识符的静态变量。
序列化版本号(serialVersionUID)的作用
当实现了Serializable的类(没有定义序列化版本号)序列化成功后进行了修改,当对这个类的实例对象进行反序列化时就会报错,因为这个对象的序列化版本号在类修改之后和之前的对应不上了(安全机制)。
解决InvalidClassException异常的反序列化方法(解决办法:增加序列化版本号):
在定义这个类时就指定一个序列化版本号,这样编译器就不会自动为其设置版本号。
//serialVersionUID = 可以为“任意数值”+L,但不能重复 private static final long serialVersionUID = 1L;