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();
	}
}

执行完成后,可以看到以下结果:

Java基础——Serializable序列化接口-LMLPHP

代码比较简单,所以就不做其他介绍,此文主要是想记录一些相关的知识点。

1、不使用Serializable接口,会发生什么错误?(好像是个弱智问题)

Java基础——Serializable序列化接口-LMLPHP

2、在类的编辑页面,IDE提示“The serializable class User does not declare a static final serialVersionUID field of type long”,其中提到的serialVersionUID具有什么作用?

Java基础——Serializable序列化接口-LMLPHP

根据Serializable接口的注释,可以得知:

请原谅我的工地英语,借助谷歌翻译勉强读懂了相关的介绍。既然看懂了,就需要亲自验证一下,以加深记忆。再上述代码以生成持久化文件的基础上,我对可序列化的类做了修改,新增了字段phone:

public class User implements Serializable {
	//构造函数省略
	private long id;
	private String userName;
	private String phone;
	//getter、setter省略
}

再次执行反序列化,得到以下结果:

Java基础——Serializable序列化接口-LMLPHP

可见,在不显示声明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,序列化运行时会跳过该字段的处理。

04-22 01:28