1,为何要实现序列化
Java平台允许我们在内存中创建可复用的Java对象,但一般情况下,只有当JVM处于运行时,这些对象才可能存在,即,这些对象的生命周期不会比JVM的生命周期更长。但在现实应用中,就可能要求在JVM停止运行之后能够保存(持久化)指定的对象,并在将来重新读取被保存的对象。实际上序列化就是将java对象转化成字节序列,这些字节可以被保存到磁盘上,也可以借助网络进行传输,序列化后的对象以二进制形式保存,这样就实现了平台的无关性,Windows平台上的序列化对象,传输到UNIX平台,可以通过反序列化得到对象。
必须注意地是,对象序列化保存的是对象的"状态",即它的公有成员,私有成员以及类名转化成字节流,再把字节流写入写入数据流中,存储到介质中。由此可知,对象序列化不会关注类中的静态变量。
2,序列化的过程
序列化机制允许将实现序列化的java对象转化成字节序列,这个过程需要借助I/O流来实现,因此只有实现了java.io.Serializable接口的类才能被序列化,JDK中,String类,Date类包装类以及枚举类型java.lang.Enum,都实现了Serializable接口,可以直接运用I/O流操作。
对于一般对象,序列化步骤,(1)创建一个对象输出流(ObjectOutputStream),她可以包装成其他类型的输出流,如文件流FileOutputSream如下代码
ObjectOuputStream oos=new ObjectOutputStream(new FileoutputStream("C:\myDocstu.txt"));这就创建了一个对象输出流,她包装了一个文件输出流,即
C:\myDocstu.txt;(2)通过对象输出流的writeObject()方法写对象,将对象写入要保存的地址当中,即C:\myDocstu.txt。条件是Student类实现Serializable接口,并创建对象Student stu=new Student();oos.writeObject(stu)可以将stu对象信息保存到磁盘上。
3, transient关键字,保密信息,未被序列化
当某个字段被声明为transient后,默认序列化机制就会忽略该字段。此处将Person类中的age字段声明为transient,如下所示,
private String name = null;
transient private Integer age = null;
private Gender gender = null;
return "[" + name + ", " + age + ", " + gender + "]";
}
}
再执行SimpleSerial应用程序,会有如下输出:
[John, null, MALE]
public static void main(String[] args) throws Exception {
File file = new File("c:\student.txt");
ObjectOutputStream oout = new ObjectOutputStream(new FileOutputStream(file));
Person person = new Person("John", 101, MALE);
oout.writeObject(person);
oout.close();
ObjectInputStream oin = new ObjectInputStream(new FileInputStream(file));
Object newPerson = oin.readObject(); // 没有强制转换到Person类型由于有Student类toString方法的存在,打印该对象,就会直接调用toString方法
oin.close();
System.out.println(newPerson);
}
}
如果仅仅只是让某个类实现Serializable接口,而没有其它任何处理的话,则就是使用默认序列化机制。使用默认机制,在序列化对象时,不仅会序列化当前对象本身,还会对该对象引用的其它对象也进行序列化,同样地,这些其它对象引用的另外对象也将被序列化,以此类推。所以,如果一个对象包含的成员变量是容器类对象,而这些容器所含有的元素也是容器类对象,那么这个序列化的过程就会较复杂,开销也较大。