Wednesday, August 26, 2015

JAVA I/O system 8/27



==============2015/8/27==================================
-        对象序列化
对象序列化主要是为了能够将对象实现轻量级持久性。“持久性”意味这一个对象的生存周期并不取决于程序是否正在执行,它可以生存于程序的调用之间。通过将一个序列化对象写入磁盘,然后再重新调用程序时恢复该对象,就能够实现持久性的效果。之所以称其为“轻量级”,是因为不能用某种“persistent”关键字来简单地定义一个对象,并让系统自动维护其他细节问题。相反,对象必须在程序中显示地序列化和反序列化还原。
Java的对象序列化将那些实现了Serializable接口的对象转换成一个字节序列,并能够在以后将这个字节序列完全恢复为原来的对象。这一过程甚至可用过网络进行;这意味着序列化机制能够自动弥补不同操作系统之间的差异。
对象序列化的概念加入语言中是为了支持两种主要特性。一是Java的远程方法调用(Remote Method Invocation, RMI,它使存活于其他计算机上的对象使用起来就像是存活在本机上一样。二是,对Java Beans来说,对象的序列化也是必要的。使用一个Bean时,一般情况下是在设计阶段对它的状态信息进行配置。这种状态信息必须保存下来,并在程序启动时进行后期恢复。
要序列化一个对象,首先要创建某些OutputStream对象,然后将其封装在一个ObjectOutputStream对象内。这时,只需调用writeObject()即可将对象序列化,并将其发送给OutputStream
要反向进行该过程,需要将一个InputStream封装在ObjectInputStream内,然后调用readObject()。我们最终获得的是一个引用,它指向一个向上转型的object,所以需要向下转型才能直接设置它们。
        // 读写的是文件
        ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("worm.out"));
        out.writeObject("Worm storage\n");
        out.writeObject(w);
        out.close(); // Also flushes output
        ObjectInputStream in = new ObjectInputStream(new FileInputStream("worm.out"));
        String s = (String)in.readObject();
        Worm w2 = (Worm)in.readObject();
        print(s+"w2 = "+w2);
       
        //读写的是字节数组
        ByteArrayOutputStream bout = new ByteArrayOutputStream();
        ObjectOutputStream out2 = new ObjectOutputStream(bout);
        out2.writeObject("Worm storage\n");
        out2.writeObject(w);
        out2.flush();
        ObjectInputStream in2 = new ObjectInputStream(new ByteArrayInputStream(bout.toByteArray()));
        s = (String)in2.readObject();
        Worm w3 = (Worm)in2.readObject();
        print(s+"w3 = "+w3);

1.       一旦从另外某个流创建了ObjectOutputStreamwriteObject()就会将对象序列化。也可以为一个String调用一个writeObject()。也可以用与DataOutputStream相同的方法写入所有基本数据类型(它们具有相同的接口)。
2.       这两段看起来相似的独立的代码。一个读写的是文件,而另一个读写的是字节数组(ByteArray)。

序列化的控制
         对于特殊需求的序列化(比如说考虑特殊的安全而难题,或者说你不希望对象的某一部分被序列化),可通过实现Externalizable接口——代替实现Serializable接口来对序列化过程进行控制。Externalizable接口继承了Serializable接口,同时增添了两个方法writeExternal()readExternal()。这两个方法会在序列化和反序列化还原的过程中被自动调用,以便于执行一些特殊操作。
1.Blips.java的例子中,Blip2的构造器不是public,而是default。这一点造成了它恢复时的异常。其原因是:在恢复对象时,会调用Blip1Blip2)的默认构造器。
这与恢复一个Serializable对象不同。对于Serializable对象,对象完全以它存储的二进制位为基础来构造,而不调用构造器。而对于一个Externalizable对象,所有普通的默认构造器都会被调用(包括字段定义时的初始化),然后调用readExternal()
public class Blip3 implements Externalizable {
    private int i;   private String s;// No initialization
    public Blip3() {
        print("Blip3 Constructor");
        // s, i not initialized
    }
    public Blip3(String x, int a) {
        print("Blip3(String x, int a)");
        s = x;
        i = a;
        // s && i initialized only in non-default constructor.
    }
    @Override
    public void readExternal(ObjectInput in) throws IOException,
            ClassNotFoundException {
        print("Blip3.readExternal");
        // You must do this:
        s = (String)in.readObject();
        i = in.readInt();
    }
    @Override
    public void writeExternal(ObjectOutput out) throws IOException {
        print("Blip3.readExternal");
        out.writeObject(s);
        out.writeInt(i);
} 
…}
3.我们如果从一个Externalizable对象继承,通常需要调用基类版本的writeExternal()readExternal()来为基类组件提供恰当的存储和恢复功能。

No comments:

Post a Comment