黑马程序员 对象序列化

来源:互联网 发布:电脑有些什么软件 编辑:程序博客网 时间:2024/05/23 05:07


-------------------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培训期待与您交流!-------------------


原创粉丝点击