文章目录
部分属性序列化和反序列化
实现部分字段序列化的方式:
- 使用transient修饰符
- 使用static修饰符
- 默认方法writerObject 和 readObject
- 使用Externalizable实现Java序列化
1、使用transient修饰符
修改实体类,将实体类中不想序列化的属性添加transient修饰词。
demo:
pojo类
package com.huang.serial;
import java.io.Serializable;
import java.util.List;
public class Student implements Serializable {
private String stuNum;
private transient String stuName;
private transient List<String> teacherList;
public Student(String stuNum, String stuName, List<String> teacherList) {
this.stuNum = stuNum;
this.stuName = stuName;
this.teacherList = teacherList;
}
public Student() {
}
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;
}
@Override
public String toString() {
return "Student{" +
"stuNum='" + stuNum + '\'' +
", stuName='" + stuName + '\'' +
", teacherList=" + teacherList +
'}';
}
}
工具类:
package com.huang.serial;
import java.io.*;
/**
* 序列化和反序列化的工具类
*/
public class MySerializeUtil {
/**
* 将对象序列化到指定文件中
* @param obj 对象
* @param fileName 文件名
*/
public static void mySerialize(Object obj , String fileName) throws IOException {
ObjectOutputStream oot = new ObjectOutputStream(new FileOutputStream(fileName) );
oot.writeObject(obj);
oot.close();
}
/**
* 从指定的文件中反序列化对象
* @param fileName
* @return
* @throws IOException
* @throws ClassNotFoundException
*/
public static Object myDeSerialize(String fileName) throws IOException, ClassNotFoundException {
ObjectInputStream oit = new ObjectInputStream(new FileInputStream(fileName));
Object object = oit.readObject();
oit.close();
return object;
}
}
测试类:
package com.huang.serial;
import java.io.IOException;
import java.util.ArrayList;
public class TestMain {
public static void main(String[] args) {
ArrayList<String> teacherList = new ArrayList<>();
teacherList.add("王老师");
teacherList.add("李老师");
Student student = new Student("1001", "小明", teacherList);
System.out.println("原始对象:" + student);
String fileName = "stu.txt";
try {
// 对象序列化
MySerializeUtil.mySerialize(student,fileName);
System.out.println("序列化完成!");
// 对象的反序列化
Object o = MySerializeUtil.myDeSerialize(fileName);
if (o instanceof Student) {
Student stu = (Student) o;
System.out.println("反序列化之后的对象" + stu);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
运行结果
原始对象:Student{stuNum='1001', stuName='小明', teacherList=[王老师, 李老师]}
序列化完成!
反序列化之后的对象Student{stuNum='1001', stuName='null', teacherList=null}
2、 使用static修饰符
static修饰符修饰的属性也不会参与序列化和反序列化。
修改实体类,将实体类中不想序列化的属性添加static修饰词。
public class Student implements Serializable {
private String stuNum;
private static String stuName;
private List<String> teacherList;
......
在对象序列化后,对象反序化前 ,对stuName 属性进行赋值
运行结果:
我们将实体类中的stuName属性添加了static修饰词,因此对象被序列化的时候忽略这个属性。通过运行结果可以看出。
3、 默认方法 writeObject 和 readObject
再次修改实体类:
public class Student implements Serializable {
private String stuNum;
private String stuName;
private List<String> teacherList;
private void writeObject(ObjectOutputStream out) throws IOException {
System.out.println("writeObject----------------");
out.writeObject(stuName);
out.writeObject(stuNum);
}
private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
System.out.println("readObject----------------");
stuNum = (String) in.readObject();
stuName = (String) in.readObject();
}
运行结果:
原始对象:Student{stuNum='1001', stuName='小明', teacherList=[王老师, 李老师]}
writeObject----------------
序列化完成!
readObject----------------
反序列化之后的对象Student{stuNum='小明', stuName='1001', teacherList=null}
源码分析:
进入Serializable 接口 的注释:
ObjectStreamClass类:在序列化(反序列化)的时候,ObjectOutputStream(ObjectInputStream) 会寻找目标类中的私有的writeObject(readObject)方法,赋值给变量 writeObjectMethod(readObjectMethod)。
是否有WriterObject 与 ReadObject 方法
没有是执行默认的方法
通过上面这两段代码可以知道,如果writeObjectMethod != null(目标类中定义了私有的writeObject 方法),那么将调用目标类中的writeObject方法,如果如果writeObjectMethod == null,那么将调用 默认的defaultWriteFields方法来读取目标类中的属性
总结一下:如果目标类中没有定义私有的writeObject或readObject方法,那么序列化和反序列化的时候将调用默认的方法来根据目标类中的属性来进行序列化和反序列化,而如果目标类中定义了私有的 writeObject或readObject方法,那么序列化和反序列化的时候将调用目标类指定的writeObject或 readObject方法来实现。
4、 Externalizable 实现java序列化
部分属性序列化的方式有多种,最后一种,就是通过实现Eexternalizable接口。
接口定义(源码):Externalizable继承自Serializable,使用Externalizable接口需要实现readExternal方法和 writeExternal方法来实现序列化和反序列化。
DEMO:
pojo类:
public class Student implements Externalizable {
private String stuNum;
private String stuName;
private List<String> teacherList;
@Override
public void writeExternal(ObjectOutput out) throws IOException {
System.out.println("writeExternal----------------");
out.writeObject(stuName);
out.writeObject(stuNum);
}
@Override
public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
System.out.println("readExternal----------------");
stuNum = (String) in.readObject();
stuName = (String) in.readObject();
}
......
运行结果:
原始对象:Student{stuNum='1001', stuName='小明', teacherList=[王老师, 李老师]}writeExternal----------------序列化完成!readExternal----------------反序列化之后的对象Student{stuNum='小明', stuName='1001', teacherList=null}
5、Serializable 和Externalizable比较
区别 | Serializable | Externalizable |
---|---|---|
实现复杂度 | 实现简单,Java对其有内建支持 | 实现复杂,由开发人员自己完成 |
执行效率 | 所有对象由Java统一保存,性能较低 | 开发人员决定哪个对象保存,可能造成速度提升 |
保存信息 | 保存时占用空间大 | 部分存储,可能造成空间减少 |
使用频率 | 高 | 低 |