黑马程序员 对象序列化


-------------------android培训 java培训期待与您交流!-------------------


对象序列化


对象序列化的目的是将对象保存到磁盘中,或允许在网络中直接传输对象,对象序列化机制运行把内存中的Java对象转换成平台无关的二进制流,从而允许把这个二进制流持久保存在磁盘上,通过网络将这种二进制流传输到另一个网络节点。其他程序一旦获得了这个二进制流,都可以将这种二进制流恢复成原来的Java对象。

对象序列化将一个Java对象写入IO流中,对象的反序列化则是从IO流中恢复该Java对象。

Java对象实现序列化的方式:

(1)实现Serializaable接口,该接口是一个标记接口,实现该接口无须实现任何方法,它只是表明该类的实例是可以序列化的。

(2)实现Externalizable接口,

 

使用对象流实现序列化

通过对象流实现序列化的步骤:

(1)创建一个ObjectOutputStream输出流。

(2)调用OjbectOutputStream对象的writeObject方法输出可序列化对象。

实例:

public classSerializableTest
   { 
    
      public static void main(String[] args)
      { 
                ObjectOutputStream oos = null;
 
            try
          { 
                 oos = new ObjectOutputStream(newFileOutputStream("e:\\test.txt")); 
                 Person p = new Person("Android",7); 
                    // 将p对象写入输出流 
                    oos.writeObject(p); 
               }
         catch (IOException e)
           { 
             
                    e.printStackTrace(); 
                 }
         finally
          { 
                  if (oos != null)
             { 
                      try
                { 
                              oos.close(); 
                         }
                catch (IOException e)
                { 
                      
                                   e.printStackTrace(); 
                       } 
                         } 
                   } 
    
           } 
   }   
    
class Personimplements Serializable
   { 
    
      private String name; 
      private int age; 
    
      public Person(String name, int age)
      { 
                super(); 
            this.name = name; 
            this.age = age; 
         } 
    
      public String getName()
          { 
                 return name; 
         } 
       
      public void setName(String name)
         { 
            this.name = name; 
         } 
    
      public int getAge()
         { 
            return age; 
         } 
    
      public void setAge(int age)
          { 
                this.age = age; 
         } 
    
   }  


反序列化的步骤:

(1)创建一个ObjectInputStream输入流。

(2)调用ObjectInputStream对象的readObject方法读取流中的对象。该方法返回一个Object类型的java对象。

实例:

 

public static void main(String[] args) { 
           ObjectInputStream ois = null; 
           try { 
               //创建一个ObjectInputStream输出流 
               ois = new ObjectInputStream(newFileInputStream("e:\\test.txt")); 
               //从流中读取一个java对象 
               Person p = (Person)ois.readObject(); 
              System.out.println("name=" + p.getName() + "  ,age=" + p.getAge()); 
           } catch (IOException e) { 
               // TODO Auto-generated catchblock 
               e.printStackTrace();  
           } catch (ClassNotFoundException e){ 
               // TODO Auto-generated catchblock 
               e.printStackTrace(); 
           } finally { 
               if (ois != null) { 
                   try { 
                       ois.close(); 
                   } catch (IOException e) { 
                       // TODO Auto-generatedcatch block 
                       e.printStackTrace(); 
                   } 
               } 
           } 
       }  


反序列化机制无须通过构造器来初始化Java对象。如果反序列化某个子类实例时,反序列化机制需要恢复其关联的父类实例,恢复这些父类实例有两种方式:使用反序列化机制;使用父类无参数的构造函数。

如果一个可序列化类有多个父类(直接父类或间接父类),则该类的所有父类要么是可序列化的,要么有无参数的构造器,否则序列化时抛出IvaalidClassException异常。

 

对象引用的序列化

当程序序列化一个对象时,如果该对象持有一个其他对象的引用,为了在反序列化时可以正常恢复该对象,则程序会顺便把他引用的其他对象也进行序列化,否则该对象不能进行序列化。

Java序列化机制采用了一种特殊的序列化算法,其内容如下:

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

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

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

注意:当使用Java序列化机制序列化可变对象时,一定要注意,只有当第一次调用wirteObject方法来输出对象时才会将对象转换为字节序列,并写出到ObjectOutputStream;在后面程序中,如果该对象的属性发送改变,即再次调用wirteObject方法输出该对象时,改变后的属性不会被输出。

 

自定义序列化

递归序列化:当对某个对象进行序列化时,系统会自动把该对象的所有属性依次进行序列化,如果某个属性引用到另一个对象,则被引用的对象也会被序列化。如果被引用的对象的属性也应用了其他对象,则被引用的对象也会被序列化。

通过在属性前加transient关键字,可以指定Java序列化时无须理会该属性,transient关键字只能用来修饰属性,不可以修饰Java程序中其他部分。比如: private  transient int  age;

但使用transient关键字修饰属性虽然很简单方便,但被transient修饰的属性将被完全隔离在序列化机制之外,这样导致在反序列化恢复Java对象时无法获得该属性值。Java提供了一种自定义序列化机制,通过这种自定义序列化机制可以让程序控制如何序列化各属性,甚至完全不序列化某些属性。

自定义序列化需要对如下个方法进行处理

(1)private  void  writeObject(java.io.ObjectOutputStream out) throws IOException;

(2)private  void readObject(java.io.ObjectInputStream  in) throwsIOException,ClassNotFoundException;

(3)private  void  readObjectNoData()throwsObjectStreamException;

writeObject方法负责写入特定类的实例的状态,以便相应的readObject方法可以恢复它。通过重写该方法,程序员可以完全获得对序列化机制的控制,程序员可以自主决定那些属性需要序列化,需要怎样序列化。默认情况下,该方法会调用out.defaultWriteObject来保存Java对象的各属性,从而可以实现序列化Java对象状态的目的。

readObject方法负责从流中读取并恢复对象属性,通过重写该方法,程序员可以完全获得对反序列化机制的控制,可以自主决定需要反序列化那些属性,以及进行怎样的反序列化。默认情况下,该方法会调用in.defaultReadObject来恢复Java对象的非静态属性,通常情况下readObject方法与readObject对应,如果writeObject方法中对Java对象的属性进行了一些处理,则应该在readObject方法中对该属性进行相应的反处理,以便正确恢复该对象。

当序列化流不完整时,readObjectNoData方法可以用来正确地初始化反序列化的对象。

Externalizable自定义序列化机制

Java还提供了另一种序列化机制,这种序列化方式完全由程序员决定存储和恢复对象数据,要实现该目的,java类必须实现Externalizable接口。

Externalizable接口定义的两个方法:

(1)void   readExternal(ObjectInput  in):需要序列化的类实现readExternal方法来实现反序列化。该方法调用DataInput(它是ObjectInput的父接口)的方法来恢复基本类似的属性值,调用ObjectInputreadObject方法来恢复引用类型的属性值。

(2)void   writeExternal(ObjectOutput  out):需要序列化的类实现writeExternal方法来保存对象的状态,该方法调用DataInput(它是ObjectInput的父接口)的方法来保存基本类型的属性值,,调用ObjectOutputwriteObject方法来保存引用类型的属性值。


-------------------android培训 java培训期待与您交流!-------------------


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值