java 序列化学习

来源:互联网 发布:php面试宝典 编辑:程序博客网 时间:2024/04/28 20:14

什么是序列化?

它是JAVA为了将对象写入到文件中产生的机制,也就是只有在对象数据流中才能用到,目的就是为了从文件中读取或者记录对象。

 

序列化就是将对象写入到“硬盘”中,该对象必须继承Serializable接口(不用实现任何方法),这个接口仅仅起到标记的作用
eg: public class Person implements Serializable{}


静态属性是不能被序列化的,因为它在“堆”中

 

因为序列化是RMI过程的参数和返回值都必须实现的机制,而RMI又是java ee技术的基础——所有分布式应用常常需要跨平台、跨网络,所以要求所有传递的参数、返回值必须实现序列化。因此序列化机制是Java EE平台基础。通常建议:程序创建每个JavaBean类都实现Serializable。

 

如果需要将某个对象保存到磁盘上或者通过网络传输,那么这个对象需要序列化,即实现Serializable接口或者Externalizable接口。

 

反序列化读取的仅仅是Java对象的数据,而不是java类,因此采用反序列化恢复java对象时,必须提供该java对象所属类的class文件,否则会引发ClassNotFoundException异常。

反序列化机制无须通过构造器来初始化Java对象。

 

如果使用序列化机制向文件中写入多个java对象,使用反序列化机制恢复对象时必须按照实际写入的顺序读取。

 

当一个可序列化类有多个父类时(包括直接父类和间接父类),这些父类要么有无参数的构造器,要么也是可序列化的——否则反序列化时将抛出InvalidClassExcepiton异常。如果父类是不可序列化的,只是带有无参数的构造器,则该父类中定义的Field值不会序列化到二进制中。

 

如果某个类的Field类型不是基本类型或String类型,而是另一个引用类型,那么这个引用类型必须是可序列化的,否则拥有该类型的Field的类也是不可序列化的。

 

Java序列化机制采用了一种特殊的序列化算法:

1、所有保存到磁盘中的对象都有一个序列化编号

2、当程序试图序列化一个对象时,程序将先检查该对象是否已经被序列化过,只有该对象从未(在本次虚拟机中)被序列化过,系统才会将该对象转换成字节序列并输出。

3、如果某个对象已经序列化过,程序将只是直接输出一个序列化编号,而不是再次重新序列化该对象。

 

如果多次序列化同一个Java对象,只有第一次序列化时才会把该java对象转换成字节序列并输出,这样可能引起一个潜在的问题——当程序序列化一个可变对象时,只有第一次使用writeObject()方法输出时才会将该对象转换成字节序列并输出,当程序再次调用writeObject()方法时,程序只是输出前面的序列化编号,即使后面该对象的Field值已经改变,改变的Field值也不会被输出。

 

当对某个对象进行序列化时,系统会自动把该对象的所有Field依次进行序列化,如果某个Field引用到另一个对象,则被引用的对象也会被序列化,如果被引用的对象的Field也引用了其他对象,则被引用的对象也会被序列化,这种情况被称为递归序列化。

 

通过在Field前面使用transient关键字修饰,可以指定java序列化时无须理会该Field。

transient关键字只能用于修饰Field,不可修饰JAVA程序中其他的部分。

eg: transient int age;

 

序列化之后的文件名命名规则:对象名称.object;因为这个文件不是用来给用户看的,打开了里面全部是乱码,但是我们应该从文件名中可以看出这个文件是存储的什么东西,作用是什么,所以文件名尤为重要

读写对象的方法示例

 

[java] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("c:\\Person.object"));  
  2. oos.writeObject(new Person(20,"huangbiao"));  
  3. oos.close();  
  4.   
  5. ObjectInputStream ois = new ObjectInputStream(new FileInputStream("c:\\Person.object"));  
  6. Person person = (Person)ois.readObject();  

 

序列号是由属性、方法计算出来的,如果属性或者是方法改变,则序列号也变了,如果读对象要捕捉找不到类的异常,当然也可以指定对象的序列号,就能找到对象
eg: public static final long serializableUID = 42L;

0 0