文章目录
⚽一.Java 序列化与反序列化
🍉 1.序列化是干啥用的? 🌈 🌈 🌈
序列化的原本意图是希望对一个Java对象作一下“变换”,变成字节序列,这样一来方便持久化存储到磁盘,避免程序运行结束后对象就从内存里消失,另外变换成字节序列也更便于网络运输和传播,所以概念上很好理解:
- 序列化:把Java对象转换为字节序列。
- 反序列化:把字节序列恢复为原先的Java对象。
而且序列化机制从某种意义上来说也弥补了平台化的一些差异,毕竟转换后的字节流可以在其他平台上进行反序列化来恢复对象。
🌈2.常见序列化与反序列化形式:
- XML
- JSON
- Protobuf
⚽ 二.序列化和反序列化地实现
🌾1.JDK类库提供的序列化API: 🥝 🥝 🥝
- java.io.ObjectOutputStream
表示对象输出流,其中writeObject(Object obj)方法可以将给定参数的obj对象进行序列化,将转换的一连串的字节序列写到指定的目标输出流中。 - java.io.ObjectInputStream
该类表示对象输入流,该类下的readObject(Object obj)方法会从源输入流中读取字节序列,并将它反序列化为一个java对象并返回。
序列化要求:
实现序列化的类对象必须实现了Serializable类或Externalizable类才能被序列化,否则会抛出异常。
💐2.Serializable 如何序列化对象?
举个例子,假如我们要对Student类对象序列化到一个名为student.txt的文本文件中,然后再通过文本文件反序列化成Student类对象:
- Student类定义
import java.io.Serializable;
public class Student implements Serializable {
private String name;
private Integer age;
private Integer score;
@Override
public String toString() {
return "Student:" + '\n' +
"name = " + this.name + '\n' +
"age = " + this.age + '\n' +
"score = " + this.score + '\n'
;
}
// ... 其他省略 ...
}
1.这段代码定义了一个 Java 类 Student,它实现了 Serializable 接口。
Serializable 接口是 Java API 中的一种标记接口,用于指示实现该接口的类可以被序列化(即可以将对象转换为字节流进行传输或持久化)。
2.Student 类有三个私有属性:name、age 和 score,分别表示学生的姓名、年龄和成绩。
3.此外,Student 类还重写了 toString() 方法,以便在打印对象时输出更易读的信息。
toString() 方法返回一个字符串,其中包括 "Student:" 这个固定前缀,以及三个字段的值,
每个字段都单独占一行,并且用 \n 分隔。
- 序列化
import java.io.FileOutputStream;
import java.io.ObjectOutputStream;
public static void serialize( ) throws IOException {
Student student = new Student();
student.setName("CodeSheep");
student.setAge( 18 );
student.setScore( 1000 );
ObjectOutputStream objectOutputStream =
new ObjectOutputStream( new FileOutputStream( new File("student.txt") ) );
objectOutputStream.writeObject( student );
objectOutputStream.close();
System.out.println("序列化成功!已经生成student.txt文件");
System.out.println("==============================================");
}
1创建一个Student 类的对象stu。
2.利用ObjectOutputStream.writeObject() 方法进行序列化,并输出到文件student.txt中。
- 反序列化
import java.io.FileInputStream;
import java.io.ObjectInputStream;
public static void deserialize( ) throws IOException, ClassNotFoundException {
ObjectInputStream objectInputStream =
new ObjectInputStream( new FileInputStream( new File("student.txt") ) );
Student student = (Student) objectInputStream.readObject();
objectInputStream.close();
System.out.println("反序列化结果为:");
System.out.println( student );
}
1. 从文件student.txt中读取字节流,并利用ObjectInputStream.readObject() 方法进行反序列化,传给对象student。
2.输出对象student。
- 运行结果
序列化成功!已经生成student.txt文件
==============================================
反序列化结果为:
Student:
name = CodeSheep
age = 18
score = 1000
其实Serializable接口也仅仅只是做一个标记用!!!它告诉代码只要是实现了Serializable接口的类都是可以被序列化的!然而真正的序列化动作不需要靠它完成。
注意事项:
- 一个实现Serializable 接口的子类也是可以被序列化的。
- 静态成员变量是不能被序列化。
- transient 标识的对象成员变量不参与序列化。
- Serializable 在序列化和反序列化过程中大量使用了反射,因此其过程会产生的大量的内存碎片。
Java 反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;
对于任意一个对象,都能够调用它的任意方法和属性;这种动态获取信息以及动态调用对象方法的功能称为Java 语言的反射机制。
简单来说,反射机制指的是程序在运行时能够获取自身的信息。
在Java 中,只要给定类的名字,就可以通过反射机制来获得类的所有信息。
- writeObject() 方法和readObject() 方法可以重写。
🌞3.触发危险函数 🌈 🌈 🌈
Student 类中通过重写readObject() 方法。反序列化时,自动调用自己的readObject() 方法,该方法中包含恶意代码,导致命令执行。