论坛首页 Java企业应用论坛

Serializable java序列化 (转)

浏览 1872 次
该帖已经被评为隐藏帖
作者 正文
   发表时间:2008-02-20  

Serializable java序列化

 
 
      1、实现Serializable回导致发布的API难以更改,并且使得package-private和private

这两个本来封装的较好的咚咚也不能得到保障了

2、Serializable会为每个类生成一个序列号,生成依据是类名、类实现的接口名、

public和protected方法,所以只要你一不小心改了一个已经publish的API,并且没有自

己定义一个long类型的叫做serialVersionUID的field,哪怕只是添加一个getXX,就会

让你读原来的序列化到文件中的东西读不出来(不知道为什么要把方法名算进去?)

3、不用构造函数用Serializable就可以构造对象,看起来不大合理,这被称为

extralinguistic mechanism,所以当实现Serializable时应该注意维持构造函数中所维

持的那些不变状态

4、增加了发布新版本的类时的测试负担

5、1.4版本后,JavaBeans的持久化采用基于XML的机制,不再需要Serializable

6、设计用来被继承的类时,尽量不实现Serializable,用来被继承的interface也不要

继承Serializable。但是如果父类不实现Serializable接口,子类很难实现它,特别是

对于父类没有可以访问的不含参数的构造函数的时候。所以,一旦你决定不实现

Serializable接口并且类被用来继承的时候记得提供一个无参数的构造函数

7、内部类还是不要实现Serializable好了,除非是static的,(偶也觉得内部类不适合

用来干这类活的)

8、使用一个自定义的序列化方法 看看下面这个保存一个双向链表的例子: public class StringList implements Serializable { ?private int size = 0; ?private Entry head = null; ? ?private static class Entry implements Serializable ?{ ? String data; ? Entry next; ? Entry previous; ?} ?...//Remainder ommitted }

 

这样会导致链表的每个元素以及元素之间的关系(双向链表之间的连接) 都保存下来,更好的方法是提供一个自定义的序列化如下:

//String List with a resonable custom serialized form class StringList implements Serializable { ? private transient int size = 0;?????? //!transient ? private transient Entry head = null;? //!transient ? ? //no longer serializable! ? private static class Entry ? { ??? String data; ??? Entry next; ??? Entry previous; ? } ? ? //Appends the specified string to the list ? public void add(String s) {/*...*/}; ? ? /** ?? * Serialize this StringList instance ?? * @author yuchifang ?? * @serialData The size of the list (the number of strings * it contains) is emitted(int), in the proper sequence ?? */ ? private void writeObject(ObjectOutputStream s) throws IOException ? { ??? s.defaultWriteObject(); ??? s.writeInt(size); ??? //Write out all elements in the proper order ??? for (Entry e = head; e != null; e = e.next) ????? s.writeObject(e.data); ? } ? ? private void readObject(ObjectInputStream s) throws IOException, ClassNotFoundException ? { ??? int numElements = s.readInt(); ??? ??? //Read in all elements andd insert them in list ??? for (int i = 0; i < numElements; i++) ????? add((String)s.readObject()); ? } ? //...remainder omitted }

9、不管你选择什么序列化形式,声明一个显式的UID:

private static final long serialVersionUID = randomLongValue;

10、不需要序列化的东西使用transient注掉它吧,别什么都留着

11、writeObject/readObject重载以完成更好的序列化

readResolve 与 writeReplace重载以完成更好的维护invariant controllers

 

文章来源:http://java.ccidnet.com/art/3737/20040111/469787_1.html

   发表时间:2008-02-20  
问题的引出:

如上所述,读写对象会有什么问题呢?比如:我要将对象写入一个磁盘文件而后再将其读出来会有什么问题吗?别急,其中一个最大的问题就是对象引用!举个例子来说:假如我有两个类,分别是A和B,B类中含有一个指向A类对象的引用,现在我们对两个类进行实例化{ A a = new A(); B b = new B(); },这时在内存中实际上分配了两个空间,一个存储对象a,一个存储对象b,接下来我们想将它们写入到磁盘的一个文件中去,就在写入文件时出现了问题!因为对象b包含对对象a的引用,所以系统会自动的将a的数据复制一份到b中,这样的话当我们从文件中恢复对象时(也就是重新加载到内存中)时,内存分配了三个空间,而对象a同时在内存中存在两份,想一想后果吧,如果我想修改对象a的数据的话,那不是还要搜索它的每一份拷贝来达到对象数据的一致性,这不是我们所希望的!

以下序列化机制的解决方案:

1.保存到磁盘的所有对象都获得一个序列号(1, 2, 3等等)

2.当要保存一个对象时,先检查该对象是否被保存了。

3.如果以前保存过,只需写入"与已经保存的具有序列号x的对象相同"的标记,否则,保存该对象

通过以上的步骤序列化机制解决了对象引用的问题!

序列化的实现

将需要被序列化的类实现Serializable接口,该接口没有需要实现的方法,implements Serializable只是为了标注该对象是可被序列化的,然后使用一个输出流(如:FileOutputStream)来构造一个ObjectOutputStream(对象流)对象,接着,使用ObjectOutputStream对象的writeObject(Object obj)方法就可以将参数为obj的对象写出(即保存其状态),要恢复的话则用输入流。

0 请登录后投票
论坛首页 Java企业应用版

跳转论坛:
Global site tag (gtag.js) - Google Analytics