java对象序列化

几个问题:

什么是java对象序列化?为什么要序列化?

如何序列化?

 

一、什么是对象序列化?为什么要序列化?

对象序列化:将java对象的状态保存成字节流,并可以在需要的时候再将对象从字节流中读出来

要序列化的原因:

1、在网络上传输的是字节流,java对象要想从网络的一端传到另外一端就需要序列化

2、对象需要持久化的时候  (想到了对象数据库,和这个有关?暂时没去了解)

 

二、java中如何实现序列化

1、自己实现序列化机制

   通过实现Externalizable接口(暂不学习)

   优势: 这种方法实现的序列化所需保存的信息比默认的少

 

2、默认序列化机制

   这种方法的序列化保存的信息有:对象的类、类签名以及非瞬态(非transient,有关键字transient的属性将不会被序列化)和非静态字段的值(静态字段属于类的)。其他对象的引用(瞬态和静态字段除外)也会导致写入那些对象  (来自JDK帮助文档)

 

3、序列化算法

   1)将对象相关的类的元数据输出

   2)递归的输出超类描述直到不再有超类

   3)开始从最顶层的超类输出实例对象

   4)递归的输出子类的实例对象

 

  总结一下就是:自下而上类描述,从上到下实例对象

 

4、最简单的实验

  

   Person类(必须实现Serializable

  

 

 
   通过ObjectOutputStream将对象转成字节流并写入到文件person.out中
 
  

 

  用winhex软件打开person.out

 

 

  各字节的意义(参考java序列化规范

     AC ED:STREAM_MAGIC. 声明使用了序列化协议。

     00 05:STREAM_VERSION 序列化协议版本

     73:TC_OBJECT 声明这是一个新的对象

     开始输出对象相关类的描述

     72:TC_CLASSDESC 声明一个新class描述开始

     00 0B:Class名字的长度 (11个字节)

     73 65 72 69 2E 50 65 72 73 6F 6E 是类的名称(seri.Person 每个字节是类名称一个字符的ASCII码)

     B7 11 2C DE 27 05 2D E1  SerialVersionUID,序列化ID,如果没有生产,算法随机生成一个8字节的ID(因为是long型的 所以是8个字节)

     02:标记号 声明该对象支持序列化

     00 02:该类包括域的个数 两个(name & age)

     49:域类型 I Int

     00 03:域名字的长度

     61 67 65:域名字 age (ASCII码)

     4C:域的类型 L Ljava/lang/String

     00 04:域名字长度

     6E 61 6D 65:域名字name

     74:TC_String 代表一个新String,用String来引用对象 (Person p)

     00 12:该String长度

     4C 6A 61 76 61 2F 6C 61 6E 67 2F 53 74 72 69 6E 67 3B:JVM标准对象签名表示法

     78:tc_endblockdata 对象块结束标志

     70:tc_null 说明没有其他超类标志 (如果还有超类会继续输出超类的描述)

     开始输出对象实例描述

     00 00 00 19:25 age域的值

     74:TC_String 代表一个新String,用String来引用name的

     00 05:5个字节

     73 74 65 76 65:steve name域的值

    

     从person.out里重新得到Person对象

    

    得到的结果是steve和25

 

三、值得关注的问题

1、序列化ID(Eclipse 下提供了两种生成策略,一个是固定的 1L,一个是随机生成一个不重复的 long 类型数据)

     Person类有个警告是因为没有加private static final long serialVersionUID = -5255369957515645471L; (是想测试一下不定义的情况下与eclipse下随机生成的是否一样,结果它们是一样的),后来查了一下都是通过JDK bin目录下的serialver.exe工具产生的,可以直接用命令行运行,得到的结果也是一样的。(根据类名、接口名、成员方法及属性等来生成的哈希字段)

    在person.out里看到的serialVersionUID是B7 11 2C DE 27 05 2D E1 转换成十进制就是 -5255369957515645471L

    作用:Java的序列化机制是通过在运行时判断类的serialVersionUID来验证版本一致性的。在进行反序列化时,JVM会把传来的字节流中的serialVersionUID与本地相应实体(类)的serialVersionUID进行比较,如果相同就认为是一致的,可以进行反序列化,否则就会出现序列化版本不一致的异常。

2、几种使用情况

   1)类A没有父类,自己实现了Serializable接口

   2)类A有父类B,且父类实现了Serializable接口

       此时类A不需要实现Serializable接口(默认是可序列化的),如果A不想序列化,则在类A中加writeObject()readObject()方法,在方法里抛出异常

  3)类A有父类B,但父类没有实现Serializable接口

    则必须在类A中显示实现writeObject()和readObject()方法来处理父类B的状态信息;

    还有一点要特别注意,在父类B中一定要有一个无参的构造函数,这是因为在反序列化的过程中并不会使用声明为可序列化的类A的任何构造函数,而是会调用其没有声明为可序列化的父类B的无参构造函数。

3、序列化的高级使用

  1)序列化 ID 的问题

  2)静态变量序列化

  3)父类的序列化与 Transient 关键字

  4)对敏感字段加密

  5)序列化存储规则

 参考 (java序列化高级知识

 

 

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值