Java序列化

序列化及文件操作

一、序列化

   对象序列化要解决的问题:简单的说就是为了将一个对象持久的保存在磁盘中,如果需要将一个对象保存到磁盘中以便于随时的读取,在这种情况下就需要对象序列化。

   对象序列化:每一个对象都是用序列号保存,相当于索引。序列化后的对象可以通过网络传送到另一台机器上。

Java中对象序列化的步骤:

1)要序列化的实例所属的类必须实现Serializable接口,这个接口没有具体的方法,是一个标记接口,代表着各类可以被序列化。

           class Employee implements Serializable{........}

           Employee harry = new Employee();

2)保存对象数据的时候需要打开ObjectOutputStream类的对象。

           ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("d.txt"));

3)将对象写入到文件中

           out.writeObject(harry);  注:私有

注:static型属性不能被序列化。

Java中将对象从文件中读回的步骤(反序列化):

1)获得一个ObjectInputStream对象

         ObjectOutputStream in = new ObjectOutputStream(new  FileInputStream("d.txt"));

2)读取这个对象

         Employee harry = (Employee) in.readObject();

保存和读取一个对象的方法就是以上步骤。具体的原理及更加复杂的问题接下来会讲到。

注:如果父类没有设置为可序列化,反序列化后,会调用父类的默认无参构造方法初始化对象,父类的属性是默认值,或者默认无参构造方法中设置的值


二、对象序列化算法

对象序列化算法如下:

写入对象:

1)给每一个对象引用都赋予一个序列号,对于任意一个对象,当第一次遇到的时候,保存期数据。

2)当这个对象第二次遇到的时候不再重复保存对象,只是保存序列号。

读回对象:

1)第一次遇到一个序列号时,构建这个对象,并初始化(用流中的数据)。保存序列号与新对象之间引用的关联。

2)当第二次遇到这个对象的时候,根据第一次建立的关联找到构建的新对象,不需要重新构建对象。


三、特殊情况

   在对象中如果有的属性不能够被序列化,可以用transient关键字标记,这样在序列化的过程中就会跳过这个属性。

   序列化机制为单个类提供了一种方式,这种方式可以向默认的读写方式中添加一些必要的功能。完成对不能序列化的类的保存。


  注重要: 在序列化过程中,虚拟机会试图调用对象类里的 writeObject 和 readObject 方法,进行用户自定义的序列化和反序列化,如果没有这样的方法,则默认调用是 ObjectOutputStream 的 defaultWriteObject 方法以及 ObjectInputStream 的 defaultReadObject 方法。用户自定义的 writeObject 和 readObject 方法可以允许用户控制序列化的过程,比如可以在序列化的过程中动态改变序列化的数值。defaultWriteObject方法只能在可序列化类中的writeObject和readObject方法中调用。

   private void writeObject(ObjectOutputStream out)

     throws IOException

   {

     out.defaultWriteObject();   //将对象中基本的元素先序列化

     out.writeDouble(double x);   //将基本类型保存

     out.writeInt(int a);

   }

四、第二种序列化方法

方法:自定义序列化,通过实现Externalizable接口,实现对象的序列化

Externalizable继承了Serializable接口,在这个接口中有两个方法readExternal和writeExternal,在这两个方法中可实现自己的机制

例:  public void writeExternal(ObjectOutput s) throws IOException

    {

      name = s.writeUTF();

      salary = s.writeDouble();

      hireDay = new Date(s.writeLong());

    }

    public void readExternal(ObjectInput s) throws IOException

    {

      name = s.readUTF();

      salary = s.readDouble();

      hireDay = new Date(s.readLong());

    }

注:在这里readExternal方法中的参数读入顺序要和writeExternal方法中的参数写出顺序相同。这两个方法可以序列化类中所有的数据,包括父类,即使父类是不可被序列化的。


注:序列化机制可以创建构造器为私有的类的新对象。readResolve的特殊序列化方法,在对象被序列化之后就会调用它,它返回一个对象,这个对象将会成为readObjict的返回值。这主向遗留代码中所有的类型安全的枚举和所有支持单例模式的类中添加。


五、版本问

   指纹:通过对类、超类、接口、域类型、和方法签名按照规范方式排序,然后将安全散列算法(SHA)应用于这些数据而获得的。版本不同对象的指纹不同。应用serialver 类名  显示一个类的指纹。

   问题:如果想把旧版本中的对象读入到使用新版本对象的程序中,或者将新版本中的对象读入到使用旧版本对象的程序中,如果不做任何修改时不能完成的,因为产生对象的两个类的指纹不相同,不能够进行匹配。

   解决:类用serialVersionUID这个静态常量来保存自己的指纹,如果一个类具有名为serialVersionUID的静态数据成员,它就不需要再人工地计算其指纹,而只需直接使用这个值。因此我们可以将新版本的serialVersionUID的值和旧版本设置成相同的。这样就解决了版本问题。

   注:当将一个旧版本的对象读入新版本中,如果数据域之间如果类型不同名字相同不会进行强制类型转换,如果数据域较少,那么忽略多余的,如果数据域较多,将多出来的赋予默认值。

注:应用对象序列化可以简便的实现对象的深拷贝。只需将对象序列化到输出流中,用字节数组保存,然后读回。

 

  











  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值