免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 1255 | 回复: 0
打印 上一主题 下一主题

关于序列化反序列化的一些资料 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2008-07-04 16:17 |只看该作者 |倒序浏览

一、    关于serialVersionUID:
1.             通常要声明一个序列化版本号,诸如: "private static final long      
serialVersionUID = 7526472295622776147L; "
2.             在新的版本中不更改serialVersionUID的值,如果更改将会引起与旧序列化对象的不兼容.
3.             新的序列化类是否可以读出老的序列化对象取决于所作更改的性质.

二、关于不兼容的更改:
1.         对类中某个变量或方法的删除:这样会便得老序列化版本的类在读新序   
列化版本的对象时会把一些新版本的值设为默认值来,这样做反而会削弱老版本完成反序列化的能力.
2.         将类的层次颠倒:这样会便得数据在数据流中的序列错误.
3.         更改非静态的field为静态的.或将nontransient 改为transient:对于默认生成的序列化,这种做法等同于删除这个field.这样做这个数据将不会被写入数据流中.当删除一个field的时候,老序列化版本将会初始化一个默认的值,这样会引起不可想象的错误.
4.         更改原来field的数据类型:
5.         更改readObject或者writeObject类,以使得它不再能读或写默认的field,或者更改它们去读/写原来版本中不可以读/写的.
6.         将可序列化类改为Externalizable类,反之亦然.
7.         将non-enum类改为enum类.
8.         将Serializabe或者Externalizabe去掉.
9.         增加一些可以产生新对象的writeReplace或者readResolve方法.

三、关于readObject 和writeObject:
1.         实现readObject和writeObject的方法必须首先调默认方法.
2.         readObject方法必须在Serializable类中实现,在反序列化结束后进行反序列化对象的检验.
3.         static 或transient域是不会进行默认的序列化的.

四、需要注意的几点:
1.     内部类尽可能少地被序列化.
2.     容器类应该经常以Hashtable 形式出现而不是大的哈希表数据结构.Hashtable这种形式通过K,V对的存储来实现序列化.
3.     对象能包含其它的对象,而这其它的对象又可以包含另外的对象。JAVA serialization能够自动的处理嵌套的对象。对于一个对象的简单的域,writeObject()直接将值写入流。而,当遇到一个对象域时,writeObject()被再次调用,如果这个对象内嵌另一个对象,那么,writeObject() 又被调用,直到对象能被直接写入流为止。程序员所需要做的是将对象传入ObjectOutputStream 的writeObject() 方法,剩下的将又系统自动完成。
4.     实现Serializable回导致发布的API难以更改,并且使得package-private和private
这两个本来封装的较好的咚咚也不能得到保障了
5.     Serializable会为每个类生成一个序列号,生成依据是类名、类实现的接口名、
public和protected方法,所以只要你一不小心改了一个已经publish的API,并且没有自己定义一个long类型的叫做serialVersionUID的field,哪怕只是添加一个getXX,就会让你读原来的序列化到文件中的东西读不出.
6.     不用构造函数用Serializable就可以构造对象,看起来不大合理,这被称为
extralinguistic mechanism,所以当实现Serializable时应该注意维持构造函数中所维
持的那些不变状态
7.     设计用来被继承的类时,尽量不实现Serializable,用来被继承的interface也不要
继承Serializable。但是如果父类不实现Serializable接口,子类很难实现它,特别是
对于父类没有可以访问的不含参数的构造函数的时候。所以,一旦你决定不实现
Serializable接口并且类被用来继承的时候记得提供一个无参数的构造函数.
8.     不管你选择什么序列化形式,声明一个显式的UID:
private static final long serialVersionUID = randomLongValue;

关于嵌套类序列化的一个例子:
import java.io. * ;
class tree implements java.io.Serializable {
public tree left;
public tree right;
public int id;
public int level;
private static int count = 0 ;
public tree( int depth) {
id = count ++ ;
level = depth;
if (depth > 0 ) {
left = new tree(depth - 1 );
right = new tree(depth - 1 );
}
}
public void print( int levels) {
for ( int i = 0 ; i 创建一个文件写入序列化树。 */
FileOutputStream ostream = new FileOutputStream( " tree.tmp " );
/**/ /* 创建输出流 */
ObjectOutputStream p = new ObjectOutputStream(ostream);
/**/ /* 创建一个二层的树。 */
tree base = new tree( 2 );
p.writeObject(base); // 将树写入流中。
p.writeObject( " LiLy is 惠止南国 " );
p.flush();
ostream.close(); // 关闭文件。
/**/ /* 打开文件并设置成从中读取对象。 */
FileInputStream istream = new FileInputStream( " tree.tmp " );
ObjectInputStream q = new ObjectInputStream(istream);
/**/ /* 读取树对象,以及所有子树 */
tree new_tree = (tree)q.readObject();
new_tree.print( 2 ); // 打印出树形结构的最上面 2级
String name = (String)q.readObject();
System.out.println( " \n " + name);
} catch (Exception ex) {
ex.printStackTrace();
}
}
}
  最后结果如下:
node 0
node 1
node 2
node 3
node 4
node 5
node 6
LiLy is 惠止南国
  可以看到,在序列化的时候,writeObject与readObject之间的先后顺序。readObject将最先write的object read出来。用数据结构的术语来讲就姑且称之为先进先出吧!
  在序列化时,有几点要注意的:
  1:当一个对象被序列化时,只保存对象的非静态成员变量,不能保存任何的成员方法和静态的成员变量。
  2:如果一个对象的成员变量是一个对象,那么这个对象的数据成员也会被保存。
  3:如果一个可序列化的对象包含对某个不可序列化的对象的引用,那么整个序列化操作将会失败,并且会抛出一个SerializableException。我们可以将这个引用标记为transient,那么对象仍然可以序列化



______________________________________________________________

以上有的是在网上找的资料,有的是自己译的.有不对的地方还请指教.


本文来自ChinaUnix博客,如果查看原文请点:http://blog.chinaunix.net/u/14137/showart_1073227.html
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP