对象序列化
Java对象序列化(Serialize)是指将Java对象写入IO流,反序列化(Deserilize)则是从IO流中恢复该Java对象。
对象序列化将程序运行时内存中的对象以字节码的方式保存在磁盘中,或直接通过网络进行传输(例如web中的HttpSession,或者J2EE中的RMI参数及返回值),以便通过反序列化的方式将字节码恢复成对象来使用。
所有可能在网络上传输对象的类都应该可序列化,通常分布式应用需要跨平台,跨网络,所以要求所有传递的参数及返回值都可序列化。
通常让需要被序列化和的类实现Serializable接口,调用序列化流对象(ObjectOutputStream/ObjectInputStream)的writeObject和readObject就可以实现序列化,
另外,通过实现Externlizable接口也可以实现序列化,但是必须要重写writeObject和readObject这两个方法才行。
使用Serializable序列化
只需要目标类实现了Serializable接口即可,不需要重写任何方法,直接调用序列化流对象(ObjectOutputStream/ObjectInputStream)的writeObject和readObject。
假如现在有一个Person类需要序列化,
1 class Person implements java.io.Serializable{ 2 public String getName() { 3 return name; 4 } 5 public void setName(String name) { 6 this.name = name; 7 } 8 public int getAge() { 9 return age; 10 } 11 public void setAge(int age) { 12 this.age = age; 13 } 14 private String name; 15 private int age; 16 17 public Person(String name, int age) { 18 System.out.println("有参数构造器"); 19 this.name = name; 20 this.age = age; 21 } 22 } 23
在测试类中,使用流对象(ObjectOutputStream)的writeObject就可以将对象序列化到具体文件,
使用流对象(ObjectInputStream)的readObject就可以从指定文件反序列化对象
1 public class ObjectIO { 2 public static void writeObject() { 3 try (ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("obj.txt"))) { 4 Person per = new Person ("孙悟空",500); 5 oos.writeObject(per); 6 } catch (IOException e) { 7 e.printStackTrace(); 8 } 9 } 10 11 public static void readObject() throws FileNotFoundException, IOException, ClassNotFoundException { 12 try (ObjectInputStream ois = new ObjectInputStream(new FileInputStream("obj.txt"))) { 13 Person p = (Person)ois.readObject(); 14 System.out.println("name: "+p.getName()+", age: "+p.getAge()); 15 } 16 } 17 18 public static void main(String[] args) throws FileNotFoundException, ClassNotFoundException, IOException { 19 writeObject(); 20 //不会调用构造器 21 readObject(); 22 } 23 } 24
执行结果,
1 有参数构造器 2 name: 孙悟空, age: 500
对象引用的序列化
如果某个类的成员变量不是基本类型,而是另一个类的引用类型(例如 Teacher 类中有个成员变量 private Person student),那么这个引用类(Person)必须是可序列化的,当前类(Teacher)才可以序列化,否则会抛出java.io.NotSerializableException异常。
对象不会被重复序列化
序列化对象将会产生一个序列号,每次序列化对象时会先检查是否已经序列化过该对象,只有未被序列化的对象才序列化,已被序列化的对象则直接输出序列号,而不会重新序列化该对象。
即:对象只有第一次序列化才生效。
例如下面的例子,
1 package io; 2 3 import java.io.FileInputStream; 4 import java.io.FileNotFoundException; 5 import java.io.FileOutputStream; 6 import java.io.IOException; 7 import java.io.ObjectInputStream; 8 import java.io.ObjectOutputStream; 9 10 11 class Person { 12 public String getName() { 13 return name; 14 } 15 public void setName(String name) { 16 this.name = name; 17 } 18 public int getAge() { 19 return age; 20 } 21 public void setAge(int age) { 22 this.age = age; 23 } 24 private String name; 25 private int age; 26 27 public Person(String name, int age) { 28 System.out.println("有参数构造器"); 29 this.name = name; 30 this.age = age; 31 } 32 } 33 34 class Teacher implements java.io.Serializable { 35 public String getName() { 36 return name; 37 } 38 public void setName(String name) { 39 this.name = name; 40 } 41 public Person getStudent() { 42 return student; 43 } 44 45 46 public class ObjectIO { 47 48 public static void writeTeacher() throws FileNotFoundException, IOException, ClassNotFoundException { 49 try (ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("teacher.txt"))) { 50 Person per = new Person("孙悟空" , 500 ); 51 Teacher t1 = new Teacher("唐僧" , per); 52 Teacher t2 = new Teacher("菩提祖师" , per); 53 54 //下面四行只会序列化三个对象,其中t1, t2 将引用同一个对象 55 oos.writeObject(t1); 56 oos.writeObject(t2); 57 oos.writeObject(per); 58 oos.writeObject(t2); 59 } catch (IOException e) { 60 e.printStackTrace(); 61 } 62 63 try (ObjectInputStream ois = new ObjectInputStream(new FileInputStream("teacher.txt"))) { 64 //反序列化需要按照序列化的顺序取对象 65 Teacher t1 = (Teacher)ois.readObject(); 66 Teacher t2 = (Teacher)ois.readObject(); 67 Person p = (Person)ois.readObject(); 68 Teacher t3 = (Teacher)ois.readObject(); 69 System.out.println("t1的student引用和p是否相同: "+ (t1.getStudent() == p)); 70 System.out.println("t2的student引用和p是否相同: "+ (t2.getStudent() == p)); 71 System.out.println("t2和t3是否是同一个对象: "+ (t2 == t3)); 72 } catch (IOException e) { 73 e.printStackTrace(); 74 } 75 } 76 77 78 public static void main(String[] args) throws FileNotFoundException, ClassNotFoundException, IOException { 79 writeTeacher(); 80 } 81 }