本期鸟菜谈谈序列化吧,很实用的技术点,操作起来也很简单。
1. 序列化Serialize实质上就是将“对象”按照某种规则封装成特定的字节流,这种字节流被同样的规则解析后在,另一个位置完整的生成该对象,也就是反序列化Deserialize。应用最多的场景可能就是将对象存储到磁盘,或者更多的是网络传输中。更简单一点,把对象看成是你网购的手机,商家给你打包后,经过物流公司再运输到你手里,你把包装拆开,得到一个完好无损的手机。商家打包过程叫做序列化,你拆包叫做反序列化,就这么简单。我们经常打交道的,就是调用HSF接口后的返回的对象,如果不进行序列化,肯定会出问题。
2. 实现起来也很简单,只要实现Serializeable接口就OK了。
下面例子讲一个对象存储到本地磁盘,这是序列化过程;再将该对象从磁盘中读出来,这就是反序列化;
先序列化对象 p到本地磁盘cat.txt中,再将其反序列化输出;
package com.taobao.mm.august; import java.io.FileOutputStream; import java.io.ObjectOutputStream; import java.io.Serializable; public class Cat implements Serializable { private static final long serialVersionUID = 4137418318779320231L; //引用类型 private String name; //基本类型 private int age; //没有提供无参的构造函数 public Cat(String name,int age){ System.out.print("带参数构造函数!"); this.name = name; this.age = age; } 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; } public static void main(String[] args) { ObjectOutputStream output = null; try{ output = new ObjectOutputStream(new FileOutputStream("cat.txt")); Cat p = new Cat("馄饨",1); //关键的一步 将对象写入 cat.txt output.writeObject(p); //关闭输出流 output.close(); }catch (Exception e) { System.out.print(e); } } }此时我们将Cat 对象p 存入本地磁盘上的cat.txt中。cat.txt文件我们一会再说,先看一下反序列化的代码。
反序列化代码:
package com.taobao.mm.august; import java.io.FileInputStream; import java.io.ObjectInputStream; /** * 用于反序列化 将cat.txt中的对象还原 */ public class GetCat { public static void main(String[] args) { ObjectInputStream input = null; try{ input = new ObjectInputStream(new FileInputStream("cat.txt")); //readObject返回值是Object 需要强制转换 Cat p = (Cat) input.readObject(); System.out.println(p.getName());// System.out.println(p.getAge());// //关闭输出流 input.close(); }catch (Exception e) { System.out.print(e); } } }输出毫无疑问,是馄饨和1。
注意,反序列化时没有输出构造器中“带参数的构造函数!”这句话,这表明反序列化时并没有调用构造函数!
关于序列化,有几点是值得注意的:
1. 如果我们向文件中输出了多个序列化的对象,反序列化时要按照之前顺序读取;
2. 如果一个可序列化类有多个父类,则该类所有父类要么是可序列化(实现了Serializable接口),要么有无参的构造函数;
3. 和类的初始化类似,反序列化的时候,会先将所有父类初始化,首先考虑使用反序列化机制,如果不可序列化(未实现Serializable接口),则调用默认构造函数,否则抛异常
4. 一个对象想要实现序列化,其中的引用成员必须也实现序列化,如Cat 中String name 我们看String类定义就可以发现,String是实现了Serializable接口的。
5. 当某个对象被多个其他对象引用时,例如类B中引用了A 对象a,类C中也引用了a,那么当着三个文件都被序列化时,每个对象仅被实例化一次,不会出现多个a对象!因为每个对象都被赋予一个唯一序列化编号,反序列化时,会首先判断该对象是否被反序列化,如果已经被实例化了,那么接下来再对该对象的反序列化,只会付给一个序列化编号。这就保证同一个对象不会被多次生成。
6. 当一个对象A a;被多次序列化时,只有第一次序列化才会把java对象a转化成字节序列并输出,即使后面对该对象a进行修改,也无法再次生成字节序列,程序只是输出第一次的序列化编号而已。
7. private static final long serialVersionUID = 4137418318779320231L;这个熟悉吧,相当于版本控制的标识,当类反序列化的时候,先检查一下本地该类class文件中的UID是不是和当前的相同,如果相同就可以进行反序列化了。
好 先写到这里吧。
对了,cat.txt还没研究呢,先把图贴出来,下次再研究一下。