Java中ObjectOutputStream的简单研究

大家都知道在庞大而复杂的java IO体系中,java.io.ObjectOutputStream和java.io.ObjectInputStream这两个类可以方便的实现对象的序列化(Serialize)和反序列化(Deserialize)。但是其中的机制究竟如何,可能没有太多人关注,今天正好有人问我object output stream中的reset是干什么的,就借机会研究一下,就做了以下的简单的实验。

    不过在实验以前先说说我的想法,我以前也很粗略的观察过object output stream序列化一个对象后生成的二进制传,大概就是类名加上一些非静态成员变量的数据,然后用自己的编码规则,也没往心里去。当时的感觉就是应用范围有限,因为这样序列化的对象只能用java自己的Object Input Stream来反序列化,所以就没有跨平台,跨语言的特性了。有时候为了将来能和其他平台通信,我甚至自己为某个类写过序列化和反序列化的方法(object-> byte[] 和byte[] -> object)。但是今天仔细看了一下,发现jdk果然比自己手写的那些简陋的代码要精巧的多。

实验的准备就是一个可以序列化的类:
class Abean implements Serializable {

    private static final long serialVersionUID = -4903107312403938616L;

    String aa;

    String bb;

}

成员变量定义成字符型,是为了查看文件方便。需要注意的就是必须实现Serializable接口,否则直接exception了。

实验代码如下:

    FileOutputStream fos = new FileOutputStream("ff");

    ObjectOutputStream oos = new ObjectOutputStream(fos);

    Abean aa = new Abean();

    aa.aa = "xx";

    aa.bb = "yy";

    for (int i = 0; i < 10; i++) {

        oos.writeObject(aa);

        oos.writeObject(aa);

//     oos.reset();

    }

    fos.close();

    FileInputStream fis = new FileInputStream("ff");

    ObjectInputStream ois = new ObjectInputStream(fis);

    for (int i = 0; i < 10; i++) {

        Abean d = (Abean) ois.readObject();

        System.out.printf("%s\t%s\n", d.aa, d.bb);

    }

测试代码也同样简单,通过控制其中一行来查看前后的区别。

    之所以设计成写入10次同样的对象,就是测试前就猜想,reset文档中所谓的“清除写入的对象的信息”,可能就意味着如果不reset,后面写入的对象能利用之前写入对象的一些信息,来减小写入的数据。

    果然,前后两次实验(注释和不注释其中那行),生成的文件的大小分别为:172字节和794字节。果然和预测一致,看来后面对象利用了前面已经写入的数据,大概后面再写入就加入了如“重复以前写入的某个对象”这样的信息,而不是再写入一次,所以文件大小减小了很多。

    再仔细分析一下两次生成的文件,第二次就是写入了10次同样的信息,其中大概包括了前面说的类名,数据成员类型,每个数据成员的值。而第一次的文件,只写了一次这些信息,之后循环出现了了18次71 00 7E 00 02(16进制的数)这个串。

    再来看下面一个实验,把原来循环语句改成

    for (int i = 0; i < 10; i++) {

        Abean aa = new Abean();

        aa.aa = "xx";

        aa.bb = "yy";

        oos.writeObject(aa);

        oos.writeObject(aa);

//     oos.reset();

    }

    也就是每次都new一个对象出来,这样不reset时文件大小为271字节,每次reset时文件大小为794字节(和之前一样)。

    再仔细看一眼两次不reset的文件,由172字节增加到271字节,一共增加了99个字节。第一个对象的信息结束时,两者是一样大的,而后面重复出现了9次一个21字节的串,也就是21*9 = 189,所以增加了90个字节。

    当然以上实验都是基于感性的认识和分析。由于java虚拟机有不同的实现,所以这套机制必然有详细的文档说明,鉴于时间原因,就不再仔细研究了。

    回到文章开头的那个问题,调用reset之后,会清除所有缓存的对象信息,再传输任何对象都会传输完整的一份内容。这显然会增加IO负担,但有些场景可能有它特殊的用处。

表:各个实验中生成文件大小的对比

实验

文件大小(字节)

reset,只new一次

172

每次rest,new一次

794

reset,每次new

271

每次reset,每次new

794

    总结一下,Object Output/Input Stream这套对象的序列化、反序列化机制确实有了不错的优化,在对象可能重复的情况下,能有效减低IO开销。但是对对象很少不重复的情况下,因为附带了类型信息,就很可能反而增加IO负担了。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值