Java SE序列化和反序列化
CAMELLIA!!! note 目录
序列化和反序列化
一、Java 序列化和反序列化概念
1.1 序列化 (Serialization)
序列化是将Java对象的状态转换为字节流的过程,以便能够将对象的状态保存到存储介质(如文件、数据库)或通过网络传输到其他Java虚拟机中。序列化使得对象能够被持久化和传输。
1.2 反序列化 (Deserialization)
反序列化是将字节流恢复成相应Java对象的过程。通过反序列化,可以从存储介质或网络中恢复对象的状态,使其重新变为可操作的Java对象。
1.3 序列化和反序列化的主要用途
- 持久化存储:将对象的状态保存到文件或数据库中,以便在以后恢复使用。
- 网络传输:通过网络将对象传输到远程主机上。
- 深度克隆:通过序列化和反序列化可以创建对象的深度拷贝。
1.4 序列化和反序列化的示例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103
| package com.camellia.io.ObjectOutputStream;
import org.junit.jupiter.api.Test; import java.io.FileOutputStream; import java.io.IOException; import java.io.ObjectOutputStream; import java.util.ArrayList; import java.util.Date; import java.util.List;
public class ObjectOutputStreamTest {
@Test public void testObjectOutputStream() { ObjectOutputStream oos = null; try { oos = new ObjectOutputStream(new FileOutputStream("src/document/object")); Date newTime = new Date(); oos.writeObject(newTime); oos.flush(); } catch (IOException e) { e.printStackTrace(); } finally { if (oos != null) { try { oos.close(); } catch (IOException e) { throw new RuntimeException(e); } } } }
@Test public void testManyObjectOutputStream() { ObjectOutputStream oos = null; try { oos = new ObjectOutputStream(new FileOutputStream("src/document/dates")); Date newTime1 = new Date(); Date newTime2 = new Date(); Date newTime3 = new Date(); Date newTime4 = new Date(); List<Date> list = new ArrayList<>(); list.add(newTime1); list.add(newTime2); list.add(newTime3); list.add(newTime4); oos.writeObject(list); oos.flush(); } catch (IOException e) { e.printStackTrace(); } finally { if (oos != null) { try { oos.close(); } catch (IOException e) { throw new RuntimeException(e); } } } } }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64
| package com.camellia.io.ObjectInputStream;
import org.junit.jupiter.api.Test;
import java.io.FileInputStream; import java.io.IOException; import java.io.ObjectInputStream; import java.util.Date; import java.util.List;
public class ObjectInputStreamTest {
@Test public void testObjectInputStream() { try (ObjectInputStream ois = new ObjectInputStream(new FileInputStream("src/document/object"))) { Object object = ois.readObject(); System.out.println(object); } catch (IOException e) { e.printStackTrace(); } catch (ClassNotFoundException e) { e.printStackTrace(); } }
@Test public void testManyObjectInputStream() { try (ObjectInputStream ois = new ObjectInputStream(new FileInputStream("src/document/dates"))) { List<Date> dates = (List<Date>) ois.readObject(); for (Date date : dates) { System.out.println(date); } } catch (IOException e) { e.printStackTrace(); } catch (ClassNotFoundException e) { e.printStackTrace(); } } }
|
二、自定义序列化和反序列化
2.1 关键点和注意事项
实现Serializable接口:要使一个类的对象可以被序列化,该类必须实现java.io.Serializable
接口。
- 当java程序中类实现了
Serializable
接口,编译器会自动给该类添加一个“序列化版本号”。
- 序列化版本号:
serialVersionUID
。
serialVersionUID:这是一个唯一标识符,用于验证在反序列化时,确保加载的类与序列化时保存的类是兼容的。建议手动定义serialVersionUID
以避免版本不兼容问题。
1
| private static final long serialVersionUID = 1L;
|
- 使用 @Serial注解可以辅助判断serialVersionUID是否写错。
如果不手动定义 serialVersionUID
,编译器会根据类的结构自动生成一个。这些生成的值依赖于类的字段和方法等细节。
即使类的小幅度变动(如添加新字段),编译器可能也会生成一个新的 serialVersionUID
,可能影响序列化的兼容性。
transient关键字:标记为transient
的字段不会被序列化。
1
| private transient int transientField;
|
静态字段:静态字段属于类而不属于对象,因此不会被序列化。
自定义序列化:如果需要控制对象的序列化过程,可以实现writeObject
和readObject
方法。
1 2 3 4 5 6 7 8 9
| private void writeObject(ObjectOutputStream oos) throws IOException { oos.defaultWriteObject(); }
private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException { ois.defaultReadObject(); }
|
安全性:反序列化时可能会带来安全风险,例如反序列化恶意代码攻击,因此在处理不受信任的数据流时要特别小心。
2.2 示例代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105
| package com.camellia.io.ObjectOutputStream;
import java.io.Serial; import java.io.Serializable;
public class StudentSerialization implements Serializable {
@Serial private static final long serialVersionUID = 9010515980424792363L;
private String name; private int age; private int id;
public StudentSerialization() {}
public StudentSerialization(String name, int age) { this.name = name; this.age = age; }
public String getName() { return name; }
public void setName(String name) { this.name = name; }
public int getAge() { return age; }
public void setAge(int age) { this.age = age; }
@Override public String toString() { return "Student{" + "name='" + name + '\'' + ", age=" + age + '}'; } }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54
| package com.camellia.io.ObjectOutputStream;
import org.junit.jupiter.api.Test;
import java.io.*;
public class CustomSerialization {
@Test public void testSerialization() { try (ObjectOutputStream oss = new ObjectOutputStream(new FileOutputStream("src/document/student"))) { StudentSerialization student = new StudentSerialization("Camellia", 23); oss.writeObject(student); oss.flush(); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } }
@Test public void Deserialization() { try (ObjectInputStream ois = new ObjectInputStream(new FileInputStream("src/document/student"))) { Object object = ois.readObject(); if (object instanceof StudentSerialization) { StudentSerialization student = (StudentSerialization) object; System.out.println(student.toString()); } } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } catch (ClassNotFoundException e) { e.printStackTrace(); } } }
|