类实现Serializable接口进行序列化和反序列化操作
来源:互联网 发布:中国家居建材 知乎 编辑:程序博客网 时间:2024/06/06 01:33
目的
类实现Serializable接口的目的主要是为了进行可持久化操作,将临时存储在内存块中的数据转换成可传输数据
SerialVersionUID属性
当我们创建A类的对象a并进行序列化传输时,如果此时我们修改了A类,增加了某些新的属性,这时候如果不对其进行判断而进行反序列化的话,将会导致运行时异常,两者类型不匹配。因此,这里使用SerialVersionUTD属性,该属性用来唯一标识一个类的版本
SerialVersionUID属性的申明方式
1.显式申明
显示声明的格式: private static final long serialVersionUID = xxxxL;
2.隐式声明
隐式声明依据: 通过包名、类名、继承关系、非私有的公共方法和属性,以及参数、返回值等因素计算出来的,保证这个值是唯一的
测试用例
1.创建序列化类
public class Person implements Serializable{ //显式声明SerialVersionUID; private static final long serialVersionUID = 55799L; private String name; private Integer age; //省略setter和getter方法}
2.创建序列化操作工具类
public class SerializeUtil{ //传输保存的文件位置 private static String file_name = "d://obj.bin"; //序列化 public void writeObj(Serializable s){ try{ ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(file_name)); oos.writeObject(s); System.out.println("序列化成功"); oos.close(); } catch(Exception e){ e.printStackTrace(); } } //反序列化 public Object readObj(){ Object obj = null; try{ ObjectInputStream input = new ObjectInputStream(new FileInputStream(file_name)); obj = input.readObejct(); input.close(); } catch(Exception e){ e.printStackTrace(); } return obj; }}
3.测试主类
public class Test{ public static void main(String[] args){ //创建持久化对象 Person per1 = new Person(); per1.setName("成兮"); per1.setAge(20); //进行序列化 SerializeUtil util = new SerializeUtil(); util.writeObj(per1); //反序列化读取数据 Person per2 = util.readObj(); //测试 System.out.println("我的名字->"+per2.getName()+" 我的年龄->"+per2.getAge()); }}
部分属性序列化问题
有时候,我们对于一个持久化类中的属性只需要序列化其中一些属性,而不是全部属性,通常我们在不需要序列化的属性前面添加关键字transient关键字,不过这标志着该持久化类将会失去分布式部署的功能
在Serializable接口类中包含了两个私有的核心方法:writeObject()和readObject(),这两个方法用来控制序列化和反序列化的过程,因此我们可以重写这两个方法来实现部分属性序列化的操作
几个核心的方法
1.private void writeObject(ObjectOutputStream out):控制序列化的过程 out.defaultWriteObject():告知JVM按照默认的规则写入对象,该语句一般写在第一行 out.writeXxx:写入相关的数据2.private void readObject(ObjectInputStream in):控制反序列化的过程 in.defaultReadObject():告知JVM按照默认的规则读取对象,该语句一般写在第一行 in.readXxx:读取相关的数据
用例:在一个工资类中包含两个属性,基本工资和绩效工资,在Person类中包含两个属性,代表员工name和工资对象,我们需要满足一个条件:在序列化中只能看到员工的name和基本工资,不能够看到员工的绩效工资,也就是不序列化绩效工资这个属性
实现代码
//Salay工资类public class Salay{ private static final long serialVersionUID = 24567L; private Double base; private Double bounse; //编写构造器 public Salay(Double base,Double bounse){ this.base = base; this.bounse = bounse; } //省略getter和setter方法 ...}//编写Person类public class Person{ private String name; private Salay salay; //编写构造器 public Person(String name,Salay salay){ this.name = name; this.salay = salay; } //省略getter和setter方法 ... //编写序列化控制方法 private void writeObject(ObjectOutputStream out)throws IOException{ out.defaultWriteObject(); //控制序列化的参数 out.writeDouble(salay.getBase()); } //编写反序列化控制方法 private void readObject(ObjectInputStream in)throws IOException{ in.defaultReadObject(); //控制反序列化的参数 salary = new Salay(in.readDouble(),0); }}//序列化操作工具类public class SerilizeUtil{ //和前面的一样 ...}//序列化操作类public class test{ public static void main(String[] args){ Salay salay = new Salay(2000,1200); Person person = new Person("成兮",salay); SerializeUtil util = new SerializeUtil(); util.writeObj(person); }}//反序列化操作类public class test2{ public static void main(String[] args){ SerializeUtil util = new SerilizeUtil(); Person person = util.readObj(); System.out.println("person.name->"+person.getName()); System.out.println("person.base->"+person.getSalay().getBase()); System.out.println("person.bounse->"+person.getSalay().getBounse()); }}//最终输出结果: person.name->成兮 person.base->2000 person.bounse->0
注意
不要在序列化类中使用构造器来初始化不可变变量,否则如果进行序列化之后再在构造器里面修改不可变变量的值,将会修改失败,这种意外通常会导致一些重大的事故,比如数据异常等
代码测试
//序列化类,包含不可变量public class Person implements Serializable{ private static final long serialVersionUID = 12345L; private String name; public Person(){ this.name = "缘分五月"; } public String getName(){ return this.name; }}//序列化操作工具类public class SerializeUtil{ ...}//序列化测试主类public class test{ public static void main(String[] args){ Person person = new Person(); SerializeUtil util = new SerializeUtil(); util.writeObj(person); System.out.println("序列化成功"); }}//反序列化测试主类public class test2{ public static void main(String[] args){ SerializeUtil util = new SerializeUtil(); Person person = util.readObj(); System.out.println("反序列化成功,person.name->"+person.getName()); }}
在默认情况下,在反序列化类中的person.name的值将会是缘分五月,而如果在反序列化之前将序列化类的构造器中的name的值修改一下呢?比如改成成兮,这个时候,我们进行反序列化得到的对象的name的值将会是什么呢?仍然是缘分五月,因为序列化时保存的是它,因此反序列化得到的依然是它
阅读全文
1 0
- 类实现Serializable接口进行序列化和反序列化操作
- Serializable 接口(序列化和反序列化)
- javaSE基础编程——序列化和反序列化操作(继承Serializable接口)
- Serializable,序列化和反序列化
- Serializable序列化和反序列化
- Serializable 序列化和反序列化
- Serializable序列化和反序列化 .
- 序列化和反序列化Serializable
- 序列化和反序列化C# [Serializable] 与[Serializable()]
- Serializable 接口与 Java 序列化与反序列化
- 序列化与反序列化及为何要实现Serializable接口
- java使用serializable进行序列化与反序列化实现对象clone(克隆)
- 对象的序列化和反序列化---使用Serializable接口
- java序列化(Serializable)的作用和反序列化
- java序列化(Serializable)的作用和反序列化
- java序列化(Serializable)的作用和反序列化
- java序列化(Serializable)的作用和反序列化
- java Serializable和Externalizable序列化反序列化详解
- 欧拉角万向节锁问题
- #416 Div.2 C. Vladik and Memorable Trip
- 嵌入式软件规范
- Spring AOP总结
- 嵌入式C语言编程规范(转载)
- 类实现Serializable接口进行序列化和反序列化操作
- 汇编语言常用指令
- Android多线程----异步消息处理机制之Handler详解
- 一周入门Kotlin(三)
- IMWeb提升营Day4 | 训练题19:顺时针打印矩阵
- bzoj1770[Usaco2009 Nov]lights 燈 高斯消元
- AR移动应用开发(三) Unity与Android的Back键冲突解决
- SpringMVC学习笔记(六):如何返回数据
- Ubuntu16.04安装IntelCaffe(根据官方文档)