Serializable序列化是将对象转成易于持久化、传输的格式的一种手段,通过将一个对象继承Serializable接口声明该类是可序列化的,然后通过ObjectOutputStream、ObjectInputStream流实现对象的存储与读取,在Serializable接口的注释中有这两个stream相关的简单的介绍。下面记录下几个例子,便于日后复习。在演示例子之前,声明一个类:
public class User implements Serializable {
//构造函数省略
private long id;
private String userName;
//getter、setter省略
}
序列化
public static void main(String[] args) {
List<User> userList = new ArrayList<User>();
userList.add(new User(1, "张三"));
userList.add(new User(2, "李四"));
try {
FileOutputStream fileOutputStream = new FileOutputStream("UserSerializeFile");
ObjectOutputStream objOutputStream = new ObjectOutputStream(fileOutputStream);
objOutputStream.writeObject(userList);
objOutputStream.close();
fileOutputStream.close();
System.out.println("序列化完成");
} catch (IOException e) {
e.printStackTrace();
}
}
执行完成后可在项目根目录看到文件UserSerializeFile。因为是以二进制的形式进行保存的,所以以普通文本的形式打开会显示乱码的形式。
反序列化
public static void main(String[] args) {
try {
FileInputStream fileInputStream = new FileInputStream("UserSerializeFile");
ObjectInputStream inputStream = new ObjectInputStream(fileInputStream);
List<User> list = (List<User>)inputStream.readObject();
for(User user : list) {
System.out.println("id: " + user.getId() + " userName: " + user.getUserName());
}
inputStream.close();
fileInputStream.close();
}catch (Exception e) {
e.printStackTrace();
}
}
执行完成后,可以看到以下结果:
代码比较简单,所以就不做其他介绍,此文主要是想记录一些相关的知识点。
1、不使用Serializable接口,会发生什么错误?(好像是个弱智问题)
2、在类的编辑页面,IDE提示“The serializable class User does not declare a static final serialVersionUID field of type long”,其中提到的serialVersionUID具有什么作用?
根据Serializable接口的注释,可以得知:
请原谅我的工地英语,借助谷歌翻译勉强读懂了相关的介绍。既然看懂了,就需要亲自验证一下,以加深记忆。再上述代码以生成持久化文件的基础上,我对可序列化的类做了修改,新增了字段phone:
public class User implements Serializable {
//构造函数省略
private long id;
private String userName;
private String phone;
//getter、setter省略
}
再次执行反序列化,得到以下结果:
可见,在不显示声明serialVersionUID的情况下,一旦修改了序列化对象,之前保存的文件将无法再进行读取和解析。
根据错误信息,我们可以知道持久化文件对应的serialVersionUID,于是我们为持久化对象增加serialVersionUID:
public class User implements Serializable {
//构造函数省略
private static final long serialVersionUID = 4164300595038901719L;
private long id;
private String userName;
private String phone;
//getter、setter省略
}
再次执行反序列化,此次程序允许则没有再出现错误。
3、部分字段不想序列化,怎么办?
声明字段时使用transient关键字。无论是序列化还是反序列化,只有添加了transient,序列化运行时会跳过该字段的处理。