博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
序列化与ArrayList 的elementData的修饰关键字transient
阅读量:4877 次
发布时间:2019-06-11

本文共 3168 字,大约阅读时间需要 10 分钟。

  transient用来表示一个域不是该对象序行化的一部分,当一个对象被序行化的时候,transient修饰的变量不会被序列化

  ArrayList的动态数组elementData被transient  修饰的  那么岂不是反序列化后的ArrayList丢失了原先的元素, 其实不然.  ArrayList在序列化的时候会调用writeObject,反序列化时调用readObject 也就是自定义序列化

  • 为什么要自定义序列化?
    • 因为ArrayList数组elementData中有未使用的空间 ,如果没有使用的空间也序列化,势必会影响性能.
  • 基本概念

    序列化:将一个对象转换成一串二进制表示的字节数组,通过保存或转移这些字节数据来达到持久化的目的。

    反序列化:将字节数组重新构造成对象。

  • 默认序列化

  序列化只需要实现java.io.Serializable接口就可以了。序列化的时候有一个serialVersionUID参数,Java序列化机制是通过在运行时判断类的serialVersionUID来验证版本一致性的。 在进行反序列化,Java虚拟机会把传过来的字节流中的serialVersionUID和本地相应实体类的serialVersionUID进行比较, 如果相同就认为是一致的实体类,可以进行反序列化,否则Java虚拟机会拒绝对这个实体类进行反序列化并抛出异常。

  • serialVersionUID有两 种生成方式:

    1、默认的1L

    2、根据类名、接口名、成员方法以及属性等来生成一个64位的Hash字段

  如果实现 java.io.Serializable接口的实体类没有显式定义一个名为serialVersionUID、类型为long的变量时,Java序列化 机制会根据编译的.class文件自动生成一个serialVersionUID,如果.class文件没有变化,那么就算编译再多 次,serialVersionUID也不会变化。换言之,Java为用户定义了默认的序列化、反序列化方法,其实就是ObjectOutputStream的defaultWriteObject方法和ObjectInputStream的defaultReadObject方法。

  • 从以上对于序列化后的二进制文件的解析,我们可以得出以下几个关键的结论:

    1、序列化之后保存的是类的信息

    2、被声明为transient的属性不会被序列化,这就是transient关键字的作用
    3、被声明为static的属性不会被序列化,这个问题可以这么理解,序列化保存的是对象的状态,但是static修饰的变量是属于类的而不是属于变量的,因此序列化的时候不会序列化它

  • 手动指定序列化过程:

    Java并不强求用户非要使用默认的序列化方式,用户也可以按照自己的喜好自己指定自己想要的序列化方式----只要你自己能保证序列化前后能得到想要的数据就好了。手动指定序列化方式的规则是:

    进行序列化、反序列化时,虚拟机会首先试图调用对象里的writeObject和readObject方法,进行用户自定义的序列化和反序列化。如果没有这 样的方法,那么默认调用的是ObjectOutputStream的defaultWriteObject以及ObjectInputStream的 defaultReadObject方法。换言之,利用自定义的writeObject方法和readObject方法,用户可以自己控制序列化和反序列 化的过程。这是非常有用的。

  • 比如:

    ArrayList的 elementData、HashMap的table

/**     * The array buffer into which the elements of the ArrayList are stored.     * The capacity of the ArrayList is the length of this array buffer. Any     * empty ArrayList with elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA     * will be expanded to DEFAULT_CAPACITY when the first element is added.     */    transient Object[] elementData; // non-private to simplify nested class access

    transient  当一个对象被序列化的时候,transient型变量的值不包括在序列化的表示中

    显然诸如 ArrayList在初始化的时候 就有空间了, 我们在操作list的时候 会存在未使用的空间,如果在序列化的时候把未使用的也序列化就不合理了

    所以ArrayList有writeObject和readObject方法自定义了序列化与反序列化: 

private void writeObject(java.io.ObjectOutputStream s)        throws java.io.IOException{        // Write out element count, and any hidden stuff        int expectedModCount = modCount;        s.defaultWriteObject();        // Write out size as capacity for behavioural compatibility with clone()        s.writeInt(size);        // Write out all elements in the proper order.        //只序列化了被使用的数据        for (int i=0; i

 

  • 序列化并不安全,因此有些场景下我们需要对一些敏感字段进行加密再序列化
  • 复杂序列化情况总结

    虽然Java的序列化能够保证对象状态的持久保存,但是遇到一些对象结构复杂的情况还是比较难处理的,最后对一些复杂的对象情况作一个总结:

      1、当父类继承Serializable接口时,所有子类都可以被序列化
      2、子类实现了Serializable接口,父类没有,父类中的属性不能序列化(不报错,数据丢失),但是在子类中属性仍能正确序列化
      3、如果序列化的属性是对象,则这个对象也必须实现Serializable接口,否则会报错
      4、反序列化时,如果对象的属性有修改或删减,则修改的部分属性会丢失,但不会报错
      5、反序列化时,如果serialVersionUID被修改,则反序列化时会失败

转载于:https://www.cnblogs.com/xxj0316/p/9554853.html

你可能感兴趣的文章
在Application中集成Microsoft Translator服务之使用http获取服务
查看>>
flask页面中Head标签内容为空问题
查看>>
Centos7 Putty SSH密钥登录
查看>>
HDU 6330--Visual Cube(构造,计算)
查看>>
小说Symbian的签名
查看>>
Objective-C中ORM的运用:实体对象和字典的相互自动转换
查看>>
高级java面试宝典
查看>>
声明,本博客文章均为转载,只为学习,不为其他用途。感谢技术大牛的技术分享,让我少走弯路。...
查看>>
centos7.1下 Docker环境搭建
查看>>
c# 导出Excel
查看>>
Status: Checked in and viewable by authorized users 出现在sharepoint 2013 home 页面
查看>>
python数据预处理
查看>>
Python之路,Day21 - 常用算法学习
查看>>
Android安全-代码安全1-ProGuard混淆处理
查看>>
部署core
查看>>
mysql 时间设置
查看>>
如何在 Xcode 中修改应用的名字
查看>>
有关交换机——熟悉原理是必须的【转载】
查看>>
ACM(数学问题)——UVa202:输入整数a和b(0≤a≤3000,1≤b≤3000),输出a/b的循环小数表示以及循环节长度。...
查看>>
【转】Android 读取doc文件
查看>>