Serializable接口实现序列化和反序列化实例
首先需要明确的概念:
序列化 :将数据结构或对象转换成二进制字节流的过程反序列化 :将在序列化过程中所生成的二进制字节流的过程转换成数据结构或者对象的过程持久化 :将数据写入文件中长久保存的过程称之为持久化序列化主要目的 :是通过网络传输对象或者说是将对象存储到文件系统、数据库、内存中。
1.创建一个学生类实现Serializable 接口:
public class Student implements Serializable {
private String stuNum;
private String stuName;
private List<String> teacherList;
public Student() {
}
public Student(String stuNum, String stuName, List<String> teacherList) {
this.stuNum = stuNum;
this.stuName = stuName;
this.teacherList = teacherList;
}
@Override
public String toString() {
return "Student{" +
"stuNum='" + stuNum + '\'' +
", stuName='" + stuName + '\'' +
", teacherList=" + teacherList +
'}';
}
public String getStuNum() {
return stuNum;
}
public void setStuNum(String stuNum) {
this.stuNum = stuNum;
}
public String getStuName() {
return stuName;
}
public void setStuName(String stuName) {
this.stuName = stuName;
}
public List<String> getTeacherList() {
return teacherList;
}
public void setTeacherList(List<String> teacherList) {
this.teacherList = teacherList;
}
}
2.创建SerializableUtil 工具类实现序列化反序列化方法
public class SerializableUtil {
public static void mySerialize(Object obj, String fileName) throws IOException {
OutputStream out = new FileOutputStream(fileName);
ObjectOutputStream objOut = new ObjectOutputStream(out);
objOut.writeObject(obj);
objOut.close();
}
public static Object myDeserialize(String fileName) throws IOException, ClassNotFoundException {
InputStream in = new FileInputStream(fileName);
ObjectInputStream objIn = new ObjectInputStream(in);
Object obj = objIn.readObject();
return obj;
}
}
3.SerializableTest 测试类,测试序列化反序列化实现
public class SerializableTest {
public static void main(String[] args) {
List<String> teacherList = new ArrayList<>();
teacherList.add("王老师");
teacherList.add("张老师");
Student stu1 = new Student("1001", "张三", teacherList);
System.out.println("原始对象:" + stu1);
String fileName = "stu01.txt";
try {
SerializableUtil.mySerialize(stu1, fileName);
System.out.println("序列化原始对象完成!OK!");
Object obj = SerializableUtil.myDeserialize(fileName);
if (obj instanceof Student) {
Student stuNew = (Student) obj;
System.out.println("反序列化之后的对象:" + stuNew);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
4.测试结果: 生成stu01.txt 文件,将数据结构成功转为二进制字节流存入文件中:
部分属性序列化和反序列化的四种方法
Transient关键字修饰
private transient String stuNum;
private transient String stuName;
private List<String> teacherList;
测试结果:
这里的stuNum 和StuName 反序列化后就是默认值null ,因为经过了transient 修饰,阻止了属性的实例化,因此反序列结果中是null 。
对于不想进行序列化的变量,可以使用 transient 关键字修饰。 transient 关键字的作用是:让实例中的属性不再序列化;当对象被反序列化时,被 transient 修饰的属性不会被持久化和恢复。需要注意的一些点:
transient 关键字只能修饰属性,不能修饰方法和类。transient 关键字修饰的属性变量,在经过反序列化之后会是相应类型的默认值,例如String 类型反序列化后就是是null ,int 类型反序列化后就是0 。
Static关键字修饰
测试:
private String stuNum;
private static String stuName;
private List<String> teacherList;
public static void main(String[] args) {
List<String> teacherList = new ArrayList<>();
teacherList.add("王老师");
teacherList.add("张老师");
Student stu1 = new Student("1001", "张三", teacherList);
System.out.println("原始对象:" + stu1);
String fileName = "stu01.txt";
try {
SerializableUtil.mySerialize(stu1, fileName);
System.out.println("序列化原始对象完成!OK!");
stu1.setStuName("张三他爹");
Object obj = SerializableUtil.myDeserialize(fileName);
if (obj instanceof Student) {
Student stuNew = (Student) obj;
System.out.println("反序列化之后的对象:" + stuNew);
}
} catch (Exception e) {
e.printStackTrace();
}
}
测试结果:
这里通过用static 关键字修饰,直接在完成初始序列化后set.stuName 可以改变学生名字,因为static 修改的属性变量不属于任何对象,是静态的,因此无论使用transient 与否,都不会被序列化。
修改默认方法writeObject和readObject
在Serializable 接口源码中有这样的说明
大概翻译一下writeObject 和readObject
测试:
public class Student implements Serializable {
private String stuNum;
private String stuName;
private List<String> teacherList;
private void writeObject(ObjectOutputStream objOut) throws IOException {
System.out.println("writeObject-----------");
objOut.writeObject(stuNum);
objOut.writeObject(stuName);
}
private void readObject(ObjectInputStream objIn) throws IOException,
ClassNotFoundException {
System.out.println("readObject-----------");
stuNum= (String) objIn.readObject();
stuName= (String) objIn.readObject();
}
}
测试结果:
因为在writeObject 和readObject 方法中,只序列化和反序列化了stuNum 和stuName ,因此teacherList 是没有序列化反序列的,所以是String 的默认值null
Externalizable实现序列化反序列化和部分序列化
Externalizable 继承自Serializable ,使用Externalizable 接口需要实现readExternal 方法和writeExternal 方法来实现序列化和反序列化。
- 源码部分
- 代码实现
private String stuNum;
private String stuName;
private List<String> teacherList;
@Override
public void writeExternal(ObjectOutput out) throws IOException {
out.writeObject(stuNum);
out.writeObject(stuName);
}
@Override
public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
stuNum= (String) in.readObject();
stuName= (String) in.readObject();
}
测试结果:
同样是因为writeExternal() 和readExternal() 只序列化和反序列化了stuNum 和stuName ,因此teacherList 是没有序列化反序列的,所以是String 的默认值null
Serializable 与 Externalizable
区别 | Serializable | Externalizable |
---|
实现复杂度 | 实现简单,Java对其有内建支持 | 实现复杂,由开发人员自己完成 | 执行效率 | 所有对象由Java统一保存,性能 | 开发人员决定哪个对象保存,可能造成速度提升 | 保存信息 | 保存时占用空间大 | 部分存储,可能造成空间减少 | 使用频率 | 高 | 偏低 |
|