类实现Serializable接口进行序列化和反序列化操作
2017-05-28 01:54
549 查看
目的
类实现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的值将会是什么呢?仍然是缘分五月,因为序列化时保存的是它,因此反序列化得到的依然是它
相关文章推荐
- 今天无意中发现JavaBean类基本都要求实现了Serializable接口,以前只是知道序列化以后,可以通过io流的方式将对象序列化和反序列化,进行存取,但不知道为什么需要序列化,今天总结一下
- .Net——使用DataContractJsonSerializer进行序列化及反序列化基本操作
- java使用serializable进行序列化与反序列化实现对象clone(克隆)
- DataSet进行序列化和反序列化操作
- .Net——使用DataContractJsonSerializer进行序列化及反序列化基本操作
- javaSE基础编程——序列化和反序列化操作(继承Serializable接口)
- 使用Serializable接口进行JAVA的序列化和反序列化
- Windows CE /SmartDeviceProject 操作Json数据实现对象序列化和反序列化
- Objective-C NSData与实现NSCoding协议进行序列化和反序列化
- .Net——使用DataContractJsonSerializer进行序列化及反序列化基本操作
- 对对象进行序列化以及反序列化操作
- java执行序列化和反序列化操作实现对象的clone
- Bridge 把一个抽象与其抽象操作的实现进行分离,这样,抽象与其抽象操作的实现可以独立进行改变
- 在.Net中通过序列化和反序列化实现对象实例化
- C#实现对象的Xml格式序列化及反序列化
- C#中将某一文件拖向应用程序后打开或进行其它操作的实现
- 如何:对 JSON 数据进行序列化和反序列化
- java 实现将传入的两个集合进行并,交,联集,差操作
- C#进行Visio二次开发之图纸缩放操作的实现
- 用C++语言实现目录文件的非递归遍历并用仿函数来进行文件操作