对象序列化

由于在程序终止时,对象都会被销毁,而如果能够在程序不运行的情况下仍然保存对象和它的信息会非常有用.虽然能够通过写入文件或是数据库来达到该目的,但是如果能将该对象声明为持久性,并且java为我们处理好所有的细节,就会十分方便.

Java的对象序列化能够将实现了serizlizable接口的对象转换成一个字节序列.并在之后将这个序列完全恢复为原来的对象.并且这一过程可通过网络进行.

private static Random rand = new Random();

    private Data[] d={
            new Data(rand.nextInt(10)),
            new Data(rand.nextInt(10)),
            new Data(rand.nextInt(10))
    };
    private Worm next;

    private char c;

    public Worm (int i,char x) {
        System.out.println("Worm constructor "+i);
        c =x;
        if(--i>0){
            next = new Worm(i,(char)(x+1));
        }
    }
    public Worm(){
        System.out.println("default constructor");
    }

    @Override
    public String toString() {
        StringBuilder result = new StringBuilder(":");
        result.append(c);
        result.append("(");
        for(Data dat:d){
            result.append(dat);
        }
        result.append(")");
        if(next!=null){
            result.append(next);
        }
        return result.toString();
    }

    public static void main(String[] args) throws IOException, ClassNotFoundException {
        Worm w = new Worm(6,'a');
        System.out.println("w + "+w);
        ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("out\worm.out"));
        out.writeObject("worm storage
");
        out.writeObject(w);
        out.close();

        ObjectInputStream in = new ObjectInputStream(new FileInputStream("out\worm.out"));
        String s = (String)in.readObject();
        Worm w2 = (Worm)in.readObject();
        System.out.println(s+"w2="+w2);
        ByteArrayOutputStream bout = new ByteArrayOutputStream();
        ObjectOutputStream out2 = new ObjectOutputStream(bout);
        out2.writeObject("worm storage
");
        out2.writeObject(w);
        out2.flush();
        ObjectInputStream in2 = new ObjectInputStream(new ByteArrayInputStream(bout.toByteArray()));
        s = (String)in2.readObject();
        Worm w3 = (Worm)in2.readObject();
        System.out.println(s+"w3 = "+w3);
    }
}


class Data implements Serializable{
    private int n;
    public Data(int n){this.n = n;}

    @Override
    public String toString() {
        return Integer.toString(n);
    }

序列化的控制

如果需要对序列化进行更精细的控制,比如一个对象的某一部分并不想被序列化或者某个子对象需要重新创建,那么通过实现Externalizable接口完成.

Externalizable 增加了writeExternal()和readExternal()两个方法.

在实现externalizable接口的情况下,反序列化时会先调用类的默认无参数构造器,然后自动执行readExternalizable.

externalizable接口与serizlizable接口的区别就在于,使用serizlizable接口时,对象的恢复是完全依赖于二进制数据的,而Externalizable则不是,它依赖于构造器以及readExternallizable()方法恢复对象.

public class Blip3 implements Externalizable{
    private int i;
    private String s;

    public Blip3(){
    }

    public void readExternal(ObjectInput in)throws IOException{
     s = (String)in.readObject;
     i = (int)in.readObject;
    }

    public void writeExternal(ObjectOutput out)…{
    out.writeObject(s);
    out.writeObject(i);
    }
}

transient(瞬时)关键字

如果有对象的字段不想被序列化保存,那么除了使用Externalizable以外还可以使用serializable但是给字段加上transient关键字

他表示这个属性不需要被处理.

由于Externalizable本身就默认不保存任何内容,因此该关键字只能与serializable一起使用

Externalizable的替代方法

如果坚持不想使用externalizable,那么使用serializable可以自己给类添加
writeObject()和readObject()方法.

而且他们都是private的,需要满足特定签名.

在调用ObjectOutputStream.writeObject()时会首先判断是否自己实现了writeObject,如果是那么就会跳过正常的序列化过程转而调用自定义的writeObject()方法.readObject()同理

可以在自己的writeObject()和readObject()内部调用defaultWriteObject或是defaultReadObject()方法调用默认的序列化过程.

使用持久性

在使用Serializable时,只要将任何对象序列化到单一流中,就可以恢复到写入时同样的对象网,而且不会出现任何意外重复的对象(比如同一对象序列化两遍,两个对象都有一个第三个对象的引用,这样的情况都可以完美恢复,不会重复生成对象).

但是如果写入到不同的序列化流中将无法保证,因此最好将所有想保存的对象放在一个容器中,进行原子性的序列化.

自动的序列化将无法对static变量正确处理,需要自己实现

serializeStaticState()和deserializeStaticState()方法,他们会在序列化反序列化时自动被调用.




原文地址:https://www.cnblogs.com/renluxiang/p/7a253082c2bc31a41f5cb34a28f8cea2.html