• 对象的序列化(串行化)分析(一)


    对象的序列化(串行化)
    序列化概念:
    (1)对象的寿命通常随着生成该对象的程序的终止而终止。有时候,可能需要将对象的状态保存下 来,在需要时再将对象恢复。我们把对象的这种能记录自己的状态以便将来再生的能力。叫作对象的持续性(persistence)。对象通过写出描述自己状 态的数值来记录自己 ,这个过程叫对象的串行化(Serialization-连续) 。
    (2)一个对象随着创建而存在,随着程序结束而结束。那 如果我要保存一个对象的状态呢?Java序列化能够将对象的状态写入byte流存储起来,也从其他地方将byte流读取出来,重新构造一个新的对象。这种 机制允许你将对象通过网络进行传播,并且可以随时把对象持久化到数据库、文件系统中。简而言之,序列化就是将一个对象的状态保存起来,而反序列化就是将已 经保存的流对象恢复成原来的对象。

    这是网上给出的两种解释。
    补充:序列化的对象只能是轻量级的持久化,想要实现持久化可以使用 hibernate,hibernate对序列化对象的持久化过程是利用缓存机制,将存储在session(就是hibernate的缓存)对象的序列化 对象通过字节流实现从内存写入硬盘的过程,在硬盘中应该是保存了一个序列化的对象流,这样也可以解释为什么hibernate的查询过程是from+持久 化的类名,获取的时候是获取到一个object对象,需要向下转型。(来自Java编程思想)

    序列化的实现:
    序列化的实现是通过 实现serializable接口,这个接口没有具体的方法,但是实现这个接口就可以实现序列化的主要原因是实现序列化是将对象转化为字节流,而转化的过 程是使用Outputstream的子类ObjectOutputstream里面的writeObject的方法,这个方法里面的具体实现如下:

     1 public final void writeObject(Object obj) throws IOException {
     2         if (enableOverride) {
     3             writeObjectOverride(obj);
     4             return;
     5         }
     6         try {
     7             writeObject0(obj, false);
     8         } catch (IOException ex) {
     9             if (depth == 0) {
    10                 writeFatalException(ex);
    11             }
    12             throw ex;
    13         }
    14     }

    这里我们可以看见第7行的时候执行了另外一个方法,这才是writeObject方法的核心,方法实现如下:

     1 private void writeObject0(Object obj, boolean unshared)
     2         throws IOException
     3     {
     4         boolean oldMode = bout.setBlockDataMode(false);
     5         depth++;
     6         try {
     7             // handle previously written and non-replaceable objects
     8             int h;
     9             if ((obj = subs.lookup(obj)) == null) {
    10                 writeNull();
    11                 return;
    12             } else if (!unshared && (h = handles.lookup(obj)) != -1) {
    13                 writeHandle(h);
    14                 return;
    15             } else if (obj instanceof Class) {
    16                 writeClass((Class) obj, unshared);
    17                 return;
    18             } else if (obj instanceof ObjectStreamClass) {
    19                 writeClassDesc((ObjectStreamClass) obj, unshared);
    20                 return;
    21             }
    22 
    23             // check for replacement object
    24             Object orig = obj;
    25             Class cl = obj.getClass();
    26             ObjectStreamClass desc;
    27             for (;;) {
    28                 // REMIND: skip this check for strings/arrays?
    29                 Class repCl;
    30                 desc = ObjectStreamClass.lookup(cl, true);
    31                 if (!desc.hasWriteReplaceMethod() ||
    32                     (obj = desc.invokeWriteReplace(obj)) == null ||
    33                     (repCl = obj.getClass()) == cl)
    34                 {
    35                     break;
    36                 }
    37                 cl = repCl;
    38             }
    39             if (enableReplace) {
    40                 Object rep = replaceObject(obj);
    41                 if (rep != obj && rep != null) {
    42                     cl = rep.getClass();
    43                     desc = ObjectStreamClass.lookup(cl, true);
    44                 }
    45                 obj = rep;
    46             }
    47 
    48             // if object replaced, run through original checks a second time
    49             if (obj != orig) {
    50                 subs.assign(orig, obj);
    51                 if (obj == null) {
    52                     writeNull();
    53                     return;
    54                 } else if (!unshared && (h = handles.lookup(obj)) != -1) {
    55                     writeHandle(h);
    56                     return;
    57                 } else if (obj instanceof Class) {
    58                     writeClass((Class) obj, unshared);
    59                     return;
    60                 } else if (obj instanceof ObjectStreamClass) {
    61                     writeClassDesc((ObjectStreamClass) obj, unshared);
    62                     return;
    63                 }
    64             }
    65 
    66             // remaining cases
    67             if (obj instanceof String) {
    68                 writeString((String) obj, unshared);
    69             } else if (cl.isArray()) {
    70                 writeArray(obj, desc, unshared);
    71             } else if (obj instanceof Enum) {
    72                 writeEnum((Enum) obj, desc, unshared);
    73             } else if (obj instanceof Serializable) {
    74                 writeOrdinaryObject(obj, desc, unshared);
    75             } else {
    76                 if (extendedDebugInfo) {
    77                     throw new NotSerializableException(
    78                         cl.getName() + "
    " + debugInfoStack.toString());
    79                 } else {
    80                     throw new NotSerializableException(cl.getName());
    81                 }
    82             }
    83         } finally {
    84             depth--;
    85             bout.setBlockDataMode(oldMode);
    86         }
    87     }

    这里放这么多代码主要是让大家看看内部实现,这里我们可以看见第73行,如果实现了serializable接口将执行序列化的操作writeOrdinaryObject(obj, desc, unshared),这里我们先不关心怎么具体实现的。到这里为止我们了解了实现serializable接口,也就是有了这个协议,我们的对象就可以序 列化了,序列化的实现交给谁呢,Outputstream的子类ObjectOutputstream来实现的。

    提到了序列化就得提一下反序列化,我们现在已经将对象转化为字节流,下来怎么让他重生呢?

    反序列化顾名思义就是将序列化对象再转回来,前面我们用OutputStream实现序列化,那我这里就是用的是InputStream来实现。

    利用Inputstream的子类ObjectInputStream的方法readObject()实现,这里需要注意的得到的是一个Object类型的对象,需要将其向下转型为我们定义的持久化对象。

    给一个小例子:

     1 public void SerializableTest (){
     2         User user = new User();
     3         File f=new File("C:","Image/user.tmp");
     4 
     5           if(f.exists()){
     6                f.delete();
     7            }
     8         //实现持久化对象的序列化
     9         user.setActive(null);
    10         user.setId(1);
    11         user.setEmailAddress("scyitgz@sina.com");
    12 
    13            FileOutputStream os=null;
    14            //ObjectOutputStream 核心类
    15            ObjectOutputStream oos=null;
    16            try {
    17                os=new FileOutputStream(f);
    18                oos=new ObjectOutputStream(os);
    19                oos.writeObject(user);
    20            } catch (IOException e) {
    21                e.printStackTrace();
    22            }
    23            try {
    24                oos.close();
    25                os.close();
    26         } catch (IOException e) {
    27             e.printStackTrace();
    28         }
    29         //实现持久化对象的反序列化
    30            FileInputStream is = null;
    31            ObjectInputStream ois = null;
    32         try {
    33             //ObjectOutputStream 核心类
    34             is = new FileInputStream(f);  
    35             ois =new ObjectInputStream(is);
    36         } catch (FileNotFoundException e) {
    37             e.printStackTrace();
    38         } catch (IOException e) {
    39             e.printStackTrace();
    40         }
    41            try {
    42             user = (User)ois.readObject();
    43             ois.close();
    44             is.close();
    45         } catch (IOException e) {
    46             e.printStackTrace();
    47         } catch (ClassNotFoundException e) {
    48             e.printStackTrace();
    49         }finally{
    50             System.out.println("user.emailAddress----"+user.getEmailAddress());
    51         }
    52     }

    以上就是序列化与反序列化的实现过程,这里只是大体的分析了一下,后面的还要分析具体的实现细节,这里只看了源码里面的一部分,还有序列化时需要注意的几点,另外hibernate框架的序列化全过程分析,transient关键字等等,敬请期待。

  • 相关阅读:
    day20:正则表达式
    day19:os模块&shutil模块&tarfile模块
    zynq之TF卡写入常见问题
    verilog之random
    quartus之ram的IP测试
    verilog之readmemb
    verilog之monitor
    verilog之display
    源自opencore的fifo的IP核解析
    veriog之四位全加器
  • 原文地址:https://www.cnblogs.com/scyitgz/p/5103697.html
Copyright © 2020-2023  润新知