Java序列化机制
java的序列化机制支持将对象序列化为本地文件或者通过网络传输至别处, 而反序列化则可以读取流中的数据, 并将其转换为java对象. 被序列化的类需要实现Serializable接口, 使用ObjectInputStream和ObjectOutputStream进行对象的读写操作.
当然, java的序列化机制并非如此简单, 以下是个人总结的一些知识点:
1. 对象读取的顺序应该和写入的顺序一致, 而且读取的次数不能超过已写入对象的个数. 比如文件中仅仅存在2个对象, 就不能连续调用3次readObject()方法, 除非调用了reset, skip等对流重新定位的方法.
2. java序列化机制针对的是对象, 而不是类. 因此只有非静态成员变量才会被序列化成二进制数据.
3. 使用transient关键字修饰的成员变量不会被序列化为二进制数据.
4. 将对象序列化为二进制数据, 将二进制数据反序列化为java对象, 这两个操作可能位于不同的应用中, 甚至也可能在不同的计算机上进行. 需要保证这两种场合下都有class文件, 在序列化处和反序列处的class文件需要完成一致, 包括包名.
5. 序列化ID的作用. 上面的Person类中定义了序列化ID: private static final long serialVersionUID = 1L;
这是一个非强制定义的静态成员, 如果不定义序列化ID, 那么eclipse会给出一个黄色的警告, 这个警告可以忽略.
考虑这样的情形: Person类定义了序列化ID, 且序列化对象时serialVersionUID的值为1, 而反序列化时serialVersionUID的值不为1, 那么此时将无法反序列化成功. 所以序列化ID可以用来限制某些用户的反序列化.
6. 父类的序列化问题. 根据java的对象实例化机制可知, 创建一个子类对象的过程中, 会创建其父类对象, 反序列化也不例外. 如果一个类实现了Serializable接口, 而其父类却没有实现Serializable接口, 那么在反序列化时, 虚拟机会调用父类的无参构造函数创建父类对象, 因此反序列化后父类成员变量的值为调用无参构造函数之后的值. 如果父类既没有实现Serializable接口, 也不存在无参构造函数, 那么在反序列化时将发生程序错误.
假设存在一个没有实现Serializable接口的Male类:
- public class Male {
- private String name;
- private int age;
- public Male() {
- }
- 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 "Male [name=" + name + ", age=" + age + "]";
- }
- }
Male的子类MaleStudent则实现了Serializable接口:
- public class MaleStudent extends Male implements Serializable {
- private int studentID;
- public MaleStudent(int studentID) {
- super();
- this.studentID = studentID;
- }
- public int getStudentID() {
- return studentID;
- }
- public void setStudentID(int studentID) {
- this.studentID = studentID;
- }
- @Override
- public String toString() {
- return "MaleStudent [studentID=" + studentID + "]";
- }
- }
则反序列化MaleStudent对象后, 其name和age属性都发生了改变:
- MaleStudent student = new MaleStudent(1);
- student.setName("coolxing");
- student.setAge(24);
- ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream(
- "male.obj"));
- out.writeObject(student);
- out.close();
- ObjectInputStream in = new ObjectInputStream(new FileInputStream(
- "male.obj"));
- MaleStudent maleStudent = (MaleStudent) in.readObject();
- System.out.println(maleStudent.getName() + ", " + maleStudent.getAge()
- + ", " + maleStudent.getStudentID());
程序的输出为:
name = null, age = 0, studentID = 1
- public class User implements Serializable {
- private static final long serialVersionUID = 1L;
- private String userName;
- private String passWord;
- public User(String userName, String passWord) {
- this.userName = userName;
- this.passWord = passWord;
- }
- public User() {
- }
- private void writeObject(ObjectOutputStream out) {
- try {
- PutField field = out.putFields();
- field.put("userName", userName);
- System.out.println("加密前: passWord = " + passWord);
- // 模拟加密
- passWord = passWord + "1";
- System.out.println("加密后: passWord = " + passWord);
- field.put("passWord", passWord);
- out.writeFields();
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
- private void readObject(ObjectInputStream in) {
- try {
- GetField field = in.readFields();
- userName = (String) field.get("userName", "");
- passWord = (String) field.get("passWord", "");
- System.out.println("读取的原始passWord = " + passWord);
- // 模拟解密
- passWord = passWord.substring(0, passWord.length() - 1);
- System.out.println("解密后的passWord = " + passWord);
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
- }
- File file = new File("user.obj");
- User user = new User("coolxing", "1987810");
- ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("user.obj"));
- out.writeObject(user);
- System.out.println(file.length());
- // 改变userName的值后再次将user对象存入文件
- user.setUserName("min");
- out.writeObject(user);
- System.out.println(file.length());
- ObjectInputStream in = new ObjectInputStream(new FileInputStream("user.obj"));
- User userFromFile1 = (User) in.readObject();
- User userFromFile2 = (User) in.readObject();
- System.out.println(userFromFile1.toString());
- System.out.println(userFromFile2.toString());
程序的输出结果为:
109
114
User [userName=coolxing, passWord=1987810]
User [userName=coolxing, passWord=1987810]
程序中调用了2次readObject()方法, 且没有出现程序错误, 由此可知确实向文件中写入了2个对象. 第二次写入user对象时, 系统发现文件中已经存在user对象, 将不再存入user对象的内容, 只写入一个引用和一些控制信息, 所以第二次写入user对象后文件的大小增加的很少, 而且userName也没有发生改变.
9. 如果一个类中包含非基本数据类型的成员变量, 那么不仅类本身需要实现Serializable接口, 类中的非基本数据类型也需要实现Serializable接口. java的一些核心类, 如String,
基本数据类型的包装类等都已经实现了Serializable接口, 使用的时候可以查看文档.
10. 对于包含集合型成员的类来说, 不仅类本身需要现Serializable接口, 集合中所存储的元素也要实现Serializable接口.
那么集合类(List, Set, Map)到底有没有实现Serializable接口呢? 这是我疑惑的地方, 文档中并没有说明. 可以确定的是,
只要集合中的元素是可序列化的, 序列化过程就不会出错.
原文地址:http://coolxing.iteye.com/blog/1222783
Java序列化机制的更多相关文章
- hadoop序列化机制与java序列化机制对比
1.采用的方法: java序列化机制采用的ObjectOutputStream 对象上调用writeObject() 方法: Hadoop 序列化机制调用对象的write() 方法,带一个DataOu ...
- 输入和输出--java序列化机制
对象的序列化 什么是Java对象的序列化? 对象序列化的目标是将对象保存到磁盘上,或允许在网络中直接传输对象.对象序列化机制允许把内存中的Java对象转换成与平台无关的二进制流,从而保存或者传输.其他 ...
- Java序列化机制和原理及自己的理解
Java序列化算法透析 Serialization(序列化)是一种将对象以一连串的字节描述的过程:反序列化deserialization是一种将这些字节重建成一个对象的过程.Java序列化API提供一 ...
- Java序列化机制和原理
Java序列化算法透析 Serialization(序列化)是一种将对象以一连串的字节描述的过程:反序列化deserialization是一种将这些字节重建成一个对象的过程.Java序列化API提供一 ...
- Java序列化机制剖析
本文转载自longdick的博文<Java序列化算法透析>,原文地址:http://longdick.iteye.com Java序列化算法透析 Serialization(序列化)是一种 ...
- Java序列化机制原理
Java序列化就是将一个对象转化为一个二进制表示的字节数组,通过保存或则转移这些二进制数组达到持久化的目的.要实现序列化,需要实现java.io.Serializable接口.反序列化是和序列化相 ...
- Java I/O系统学习系列五:Java序列化机制
在Java的世界里,创建好对象之后,只要需要,对象是可以长驻内存,但是在程序终止时,所有对象还是会被销毁.这其实很合理,但是即使合理也不一定能满足所有场景,仍然存在着一些情况,需要能够在程序不运行的情 ...
- 细看Java序列化机制
概况 在程序中为了能直接以 Java 对象的形式进行保存,然后再重新得到该 Java 对象,这就需要序列化能力.序列化其实可以看成是一种机制,按照一定的格式将 Java 对象的某状态转成介质可接受的形 ...
- java 序列化机制
package stream; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io ...
随机推荐
- POJ 1743 后缀数组
题目链接:http://poj.org/problem?id=1743 题意:给定一个钢琴的音普序列[值的范围是(1~88)],现在要求找到一个子序列满足 1,长度至少为5 2,序列可以转调,即存在两 ...
- 使用recon/domains-hosts/baidu_site模块,枚举baidu网站的子域
使用recon/domains-hosts/baidu_site模块,枚举baidu网站的子域 [实例3-1]使用recon/domains-hosts/baidu_site模块,枚举baidu网站的 ...
- 疯狂java笔记(五) - 系统交互、System、Runtime、Date类
一.程序与用户交互(Java的入口方法-main方法): 运行Java程序时,都必须提供一个main方法入口:public static void main(String[] args){} publ ...
- js事件绑定细节说明
javascript绑定事件: 经常用jQuery去写,时间长了对原生态的js事件绑定的知识会慢慢淡化或者遗忘了,必须翻出来再次总结,今天再次把js原生态事件的处理做个总结. 从最初开始,谁刚接触ja ...
- 向Web开发人员推荐12款优秀的 Twitter Bootstrap 组件和工具
http://www.cnblogs.com/lhb25/archive/2012/09/11/resources-that-complement-twitter-bootstrap.html
- ccc prefab
MonsterPrefab.js var Helpers = require('Helpers'); cc.Class({ extends: cc.Component, properties: { s ...
- awk 学习
1. awk用例 今天用awk来统计一个字符出现的次数,总是比实际多一个.查了半天才发现问题所在. 文本tt.txt如下: <lst name="responseHeader" ...
- POJ 1141 Brackets Sequence(DP)
题目链接 很早 很早之前就看过的一题,今天终于A了.状态转移,还算好想,输出路径有些麻烦,搞了一个标记数组的,感觉不大对,一直wa,看到别人有写直接输出的..二了,直接输出就过了.. #include ...
- 总结新系统部署时,Oracle的一些注意事项:
1.Oracle安装时,要选择字符集为中文编码,数据库重要角色设置密码时,不要用数字开头,不然后面会报一些错误提示 2.emp导出的数据dmp格式,导入时要在服务器导入,具体没有试,要找机会试试,转化 ...
- 开源工作流引擎CCFlow 学习专区
http://bbs.ccflow.org/index.aspx 官网:http://www.ccflow.org/