Java对象序列化(Object Serialization)

来源:互联网 发布:加入淘宝充值平台赚钱 编辑:程序博客网 时间:2024/05/01 11:32

Java1.1中实现了Serializable接口的对象都可被转换成一系列字节,并可完全恢复成原状。Java中的两个特性运用了对象序列化:远程调用方法(RMI),Java Beans


要序列化一个对象(其类已实现Serializable接口),需要创建一些OutputStream对象,将其封装到ObjectOutputStream对象中,调用writeObject()方法即可将序列化的对象发生到OutputStream中,比如文件、String、网络等。当要恢复对象时,只需将InputStream封装到ObjectInputStream对象中,调用readObject()方法即可,当然此时必须上溯造型到原始类型。

1. Serializable接口实例

package com.test;import java.io.*;class Data implements Serializable {private int i;Data(int x) { i = x; }public String toString() {return Integer.toString(i);}}public class Serial implements Serializable {//Generate random intprivate static int r() {return (int)(Math.random() * 10);}private Data[] d = {new Data(r()), new Data(r()), new Data(r())};private Serial next;private char c;Serial(int i, char x) {System.out.println(" Serial constructor: " + i);c = x;if (--i >0)next = new Serial(i, (char)(x+1));}Serial() {System.out.println("Default constructor");}public String toString() {String s = ":" + c + "(";for (int i = 0; i < d.length; i++) {s += d[i].toString();}s += ")";if (next != null)s += next.toString();return s;}public static void main(String[] args) {Serial w = new Serial(6, 'e');System.out.println("w = " + w);try {//write the serialized objects to fileObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("serial.out"));out.writeObject("Serial test");out.writeObject(w);out.close(); //will also flush output//read and restore serialized objects from fileObjectInputStream in = new ObjectInputStream(new FileInputStream("serial.out"));String s = (String)in.readObject();Serial w2 = (Serial)in.readObject();System.out.println(s + ", w2 = " + w2);} catch (Exception e) {e.printStackTrace();}try {//write the serialized objects to memoryByteArrayOutputStream bout = new ByteArrayOutputStream();ObjectOutputStream out = new ObjectOutputStream(bout);out.writeObject("Serial test");out.writeObject(w);out.flush();//read and restore from memoryObjectInputStream in = new ObjectInputStream(new ByteArrayInputStream(bout.toByteArray()));String s = (String)in.readObject();Serial w3 = (Serial)in.readObject();System.out.println(s + ", w3 = " + w3);} catch (Exception e) {e.printStackTrace();}}}
在读取并恢复Serializable对象的时候不会允许构建器,而且对象序列化没有用到IO系统的Reader和Writer,而是使用Java1.0的InputStream和OutputStream体系。


2. Externalizable接口

实现了Serializable接口的对象序列化时,默认会将类中所有字段包含进去。但是有时涉及安全问题,有些字段我们不想被序列化,这时可使用Externalizable接口控制序列化过程。Externalizable接口扩展了Serializable接口,并添加了两个方法writeExternal()和readExternal()。在序列化和恢复的过程中会自动调用这两个方法,我们可以通过改写他们控制序列化和恢复过程。

实例1,实现Externalizable接口的对象在恢复是会调用类的默认构建器,注意Blip2的默认构建器不是public的,这样会导致调用权限不够而产生异常

package com.test;import java.io.*;import java.util.*;class Blip1 implements Externalizable {public Blip1() {System.out.println("Blip1 constructor");}public void writeExternal(ObjectOutput out) throws IOException {System.out.println("Blip1.writeExternal");}public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {System.out.println("Blip1.readExternal");}}class Blip2 implements Externalizable {Blip2() {System.out.println("Blip2 constructor");}public void writeExternal(ObjectOutput out) throws IOException {System.out.println("Blip2.writeExternal");}public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {System.out.println("Blip2.readExternal");}}public class External {public static void main(String[] args) {System.out.println("Constructing objects: ");Blip1 b1 = new Blip1();Blip2 b2 = new Blip2();try {//write serialzed objectsObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("Blips.out"));System.out.println("Saving objects: ");out.writeObject(b1);out.writeObject(b2);out.close();//read and restore objectsObjectInputStream in = new ObjectInputStream(new FileInputStream("Blips.out"));System.out.println("Recovering b1:");b1 = (Blip1)in.readObject();//following will throw exception //as Blip2's default constructor is not public//b2 = (Blip2)in.readObject();} catch (Exception e) {e.printStackTrace();}}}


实例2,在readExternal和writeExternal中控制序列化过程

package com.test;import java.io.*;import java.util.*;public class External2 implements Externalizable {int i;String s; //not initializepublic External2() {System.out.println("External2 constructor");}public External2(String x, int a) {System.out.println("External2(String x, int a)");s = x;i = a;}public String toString() { return s + i; }public void writeExternal(ObjectOutput out) throws IOException {System.out.println("External2.writeExternal");//write the fields you want to serialize//you can only serialize some fieldsout.writeObject(s);out.writeObject(i);}public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {System.out.println("External2.readExternal");//Restore the fields that are serializeds = (String)in.readObject();i = in.readInt();}public static void main(String[] args) {System.out.println("Constructing objects: ");External2 e2 = new External2("A string", 42);System.out.println(e2.toString());try {ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("external2.out"));System.out.println("Saving object: ");out.writeObject(e2);out.close();//restore objectObjectInputStream in = new ObjectInputStream(new FileInputStream("external2.out"));System.out.println("Recovering e2:");e2 = (External2)in.readObject();System.out.println(e2.toString());} catch (Exception e) {e.printStackTrace();}}}


3. transient关键字

实现Serializable接口的类序列化时默认所有fields都会被序列化,transient关键字可以关闭fields的序列化。设置成transient的字段不参与序列化,恢复时简单的设置成默认值,如int 0, 对象句柄 null。


4. writeObject()和readObject()方法代替Externalizable

实现Serializable接口,并添加writeObject()和readObject()方法也可以控制序列化过程。但是这两个方法在类中都被定义成private,按理说外部类是不能调用的,这里序列化过程绕过了检查,这种绕过检查的机制我们普通用户是不可能接触到的。。。

private void writeObject(ObjectOutputStream stream) throws IOException;private void readObject(ObjectInputStream stream) throws IOException, ClassNotFoundException;


实例:

//: SerialCtl.java //Controlling serialization by adding your own //writeObject() and readObject() methods. import java.io.*; public class SerialCtl implements Serializable { String a; transient String b; public SerialCtl(String aa, String bb) {  a = "Not Transient: " + aa;  b = "Transient: " + bb; } public String toString() {  return a + "\n" + b; } private void   writeObject(ObjectOutputStream stream)    throws IOException {  stream.defaultWriteObject();  stream.writeObject(b); } private void   readObject(ObjectInputStream stream)    throws IOException, ClassNotFoundException {  stream.defaultReadObject();  b = (String)stream.readObject(); } public static void main(String[] args) {  SerialCtl sc =     new SerialCtl("Test1", "Test2");  System.out.println("Before:\n" + sc);  ByteArrayOutputStream buf =     new ByteArrayOutputStream();  try {    ObjectOutputStream o =      new ObjectOutputStream(buf);    o.writeObject(sc);    // Now get it back:    ObjectInputStream in =      new ObjectInputStream(        new ByteArrayInputStream(          buf.toByteArray()));    SerialCtl sc2 = (SerialCtl)in.readObject();    System.out.println("After:\n" + sc2);  } catch(Exception e) {    e.printStackTrace();  } } } ///:~



0 0
原创粉丝点击