1、对象流的基本概念 存在既有意义,对象流可以帮助我们将内存中的Java对象保存到本地磁盘,即字节序列。这种将Java对象转化为一个字节序列,就叫做对象序列化。反之,将一个序列文件转化为Java对象,这个过程称作反序列化。 听起来对象流很高大上,其实很简单。在Java程序运行过程中,Java对象的属性值都存储在内存,程序结束后释放内存,一股青烟后,任何数据都会消失,为了将内存中的Java对象的属性状态保存到本地磁盘,于是对象流就应运而生。
2、Serializable接口 说到对象序列化,必须要讲到Serializable接口。Java对象所属的类必须实现Serializable接口。实现这个接口不必重写任何方法,其只作为可序列化的标识。 小编建议每一个实现Serializable接口的对象类,需要显示添加一个常数serialVersionUID,表明该类的版本。如果不添加该常数,对象序列化时会根据对象类的信息计算出默认的serialVersionUID的值。 serialVersionUID就像我们的身份证一样,每次序列化时,java编译器会根据serialVersionUID确认java对象类。反序列化时,如果serialVersionUID不一致,会抛出InvalidClassException异常。 Serializable接口稍后还会讲到,我们接着学习对象流的操作。
3、对象流之ObjectOutputStream对象序列化 ObjectOutputStream可以将对象进行序列姝耒匝揎化的输出流。示例代码如下://ObjectOutputStreamDemo类代码 public class ObjectOutputStreamDemo{/* * void writeObject() * 将特定的对象转化为字节序列 */ @Test public void testOOS() throws Exception{ FileOutputStream fos = new FileOutputStream("boy.obj"); //构造方法ObjectOutputSteam(OutputStream out) ObjectOutputStream oos = new ObjectOutputStream(fos); Person boy = new Person("Peter",12,"男"); oos.writeObject(boy); System.out.println("完成序列化"); oos.close(); }} //Java对象类代码public class Person implements Serializable { private static final long serialVersionUID = 1L; private String name; private int age; private String gender; public Person() { super(); } public Person(String name, int age, String gender) { super(); this.name = name; this.age = age; this.gender = gender; } 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 String getGender() { return gender; } public void setGender(String gender) { this.gender = gender; } @Override public String toString() { return "name=" + name + ", age=" + age + ", gender=" + gender ; }}注意:可以将上述代码片段粘贴到本地,运行测试,供大家参考,如果有问题可以联系小编。
4、对象流之ObjectInputStream对象反序列化 ObjectInputStream可以将序列化转换成醑穿哩侬对象。示例代码如下://ObjectInputStreamDemo类public class ObjectInputStreamDemo{/* * Object readObject(); * 将对象序列化转换为对象 */ @Test public void testOIS() throws Exception{ FileInputStream fis = new FileInputStream("boy.obj"); ObjectInputStream ois = new ObjectInputStream(fis); //Object readObject()读取二进制文件转换成对象 Person boy = (Person)ois.readObject(); System.out.println(boy); System.out.println("反序列化操作完毕"); ois.close();}}
5、实现Serializable接口注意事项 Java对象类实现Serializable接口后,显式声明serialVersionUID,确定Java对象所属类的版本。如磨营稼刻果不显式声明,Java编译器会根据Java对象类的结构计算生成默认的serialVersionUID,这意味着每次修改Java对象类会重新生成默认的serialVersionUID,这样导致反序列化失败。 下面代码有几处进行少量修改 1)、显式声明的常量serialVersionUID注释掉; 2)、然后修改Person类,添加体重(weight)的属性; 3)、最后运行反序列化代码 4)、查看运行结果。示例代码如下://ObjectOutputStreamDemo类代码如下 public class ObjectOutputStreamDemo{/* * void writeObject() * 将特定的对象转化为字节序列 */ @Test public void testOOS() throws Exception{ FileOutputStream fos = new FileOutputStream("boy.obj"); //构造方法ObjectOutputSteam(OutputStream out) ObjectOutputStream oos = new ObjectOutputStream(fos); Person boy = new Person("Peter",12,"男",50); oos.writeObject(boy); System.out.println("完成序列化"); oos.close(); }} //ObjectInputStreamDemo类如下public class ObjectInputStreamDemo{/** Object readObject();* 将对象序列化转换为对象*/@Testpublic void testOIS() throws Exception{ FileInputStream fis = new FileInputStream("boy.obj"); ObjectInputStream ois = new ObjectInputStream(fis); //Object readObject()读取二进制文件转换成对象 Person boy = (Person)ois.readObject(); System.out.println(boy); System.out.println("反序列化操作完毕"); ois.close();}}//Java对象类代码如下public class Person implements Serializable { //private static final long serialVersionUID = 1L; private String name; private int age; private String gender; private int weight; public Person() { super(); } public Person(String name, int age, String gender,int weight) { super(); this.name = name; this.age = age; this.gender = gender; this.weight = weight; } 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 String getGender() { return gender; } public void setGender(String gender) { this.gender = gender; } public int getWeight(){ return weight; } public void setWeight(int weight){ this.weight = weight; } @Override public String toString() { return "name=" + name + ", age=" + age + ", gender=" + gender +", weight="+weight ; } }分析:对象序列化操作,对象所属类除了要实现Serializable接口外,还要显式声明serialVersionUID,确保对象类的版本一致,修改类信息后不会由于默认的serialVersionUID不一致而报错。思考:大家可以将上述代码拷贝到本地运行测试,serialVersionUID不变,删除Person类的属性查看运行结果。