文档章节

ArrayList中elementData为什么被transient修饰?

群星纪元
 群星纪元
发布于 2019/04/06 17:55
字数 1070
阅读 70
收藏 3

  Java的ArrayList中,定义了一个数组elementData用来装载对象的,具体定义如下:

/**
 * 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又是可序行化的类,elementData是ArrayList具体存放元素的成员,用transient来修饰elementData,岂不是反序列化后的ArrayList丢失了原先的元素?
       其实玄机在于ArrayList中的两个方法:

/**
 * Save the state of the <tt>ArrayList</tt> instance to a stream (that
 * is, serialize it).
 *
 * @serialData The length of the array backing the <tt>ArrayList</tt>
 *             instance is emitted (int), followed by all of its elements
 *             (each an <tt>Object</tt>) in the proper order.
 */
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<size; i++) {
        s.writeObject(elementData[i]);
    }
 
    if (modCount != expectedModCount) {
        throw new ConcurrentModificationException();
    }
}

 

/**
 * Reconstitute the <tt>ArrayList</tt> instance from a stream (that is,
 * deserialize it).
 */
private void readObject(java.io.ObjectInputStream s)
    throws java.io.IOException, ClassNotFoundException {
    elementData = EMPTY_ELEMENTDATA;
 
    // Read in size, and any hidden stuff
    s.defaultReadObject();
 
    // Read in capacity
    s.readInt(); // ignored
 
    if (size > 0) {
        // be like clone(), allocate array based upon size not capacity
        ensureCapacityInternal(size);
 
        Object[] a = elementData;
        // Read in all elements in the proper order.
        for (int i=0; i<size; i++) {
            a[i] = s.readObject();
        }
    }
}

       ArrayList在序列化的时候会调用writeObject,直接将size和element写入ObjectOutputStream;反序列化时调用readObject,从ObjectInputStream获取size和element,再恢复到elementData。
       为什么不直接用elementData来序列化,而采用上诉的方式来实现序列化呢?原因在于elementData是一个缓存数组,它通常会预留一些容量,等容量不足时再扩充容量,那么有些空间可能就没有实际存储元素,采用上诉的方式来实现序列化时,就可以保证只序列化实际存储的那些元素,而不是整个数组,从而节省空间和时间。

 

transient分析
注意到的是ArrayList和LinkedList中的一些变量被transient关键字修饰。如ArrayList中的elementData数组,LinkedList中指向头结点和尾结点的指针等。下面解释一下transient关键字的作用:

java的serialization提供了一种持久化对象实例的机制。当持久化对象时,可能有一个特殊的对象数据成员,我不想用serialization机制来保存它。为了在一个特定对象的域上关闭serialization,可以在这个域前加上关键字transient。transient是一个关键字,用来表示一个于不是该对象串行化的一部分。当一个对象被串行化的时候,被transient关键字修饰的变量的值不包括在串行化的表示中,非transient型的变量是被包括进去的。

那么既然用于保存数据的变量都被transient修饰,ArrayList和LinkedList还能不能被序列化呢?

答案是可以的。对于ArrayList来说,如果不把elementData申明为transient类型,那么序列化的时候里面的数据都会被序列化,但是elementData这个数组很大程序是存在空值的情况(即size《length),这时如果序列化就会导致磁盘空间被浪费。为了解决这个问题,ArrayList将elementData申明为transient,自己重写了writeObject方法,保证只序列化elementData中有数据的那部分,ArrayList中的writeObject方法如下:

(见上文)

注意的是这里面也用到了modCount,如果不一致说明这段时间集合发生了改变,抛出异常。

LinkedList中的序列化和ArrayList中的序列化还不一样,LinkedList中不会存在说有多余的元素这种说法,但是由于LinkedList中申明为transient类型的数据都可以不用进行序列化,所以进行申明,比如分别指向头结点和尾结点的first和last指针。

本文转载自:https://blog.csdn.net/zero__007/article/details/52166306

上一篇: 泛型
群星纪元
粉丝 48
博文 456
码字总数 44497
作品 0
朝阳
高级程序员
私信 提问
加载中

评论(0)

Java关键字 - transient

今天看和的代码时,发现一个细节不一样,它们实际用来存储元素的前面的修饰关键字不一样: 以前听到最多的就是说,是线程安全的,是非线程安全的。 在好奇心的驱使下,翻书找到了一段解释的话...

Jacktanger
2019/05/19
47
0
jdk1.6的集合源码阅读之ArrayList

简述 ArrayList其实就是动态数组,是Array的复杂版本,动态扩容和缩容,灵活的设置数组的大小,等等。 其定义如下 而AbstractCollection实现了Collection的部分方法和AbstractList继承了该A...

双月通天
2016/08/23
47
0
源码之ArrayList和Vector

父类介绍 说明: 继承AbstractList,实现List接口,提供了add、remove、indexOf、get等相关方法 实现RandomAccess接口,提供了随机访问功能。在ArrayList中,我们即可以通过元素的序号快速获...

yimingkeji
2019/01/06
27
0
Java基础知识之ArrayList知识点总结

本文包含常见的ArrayList的基本知识。在一些主题下也自然地引出了Colletion类的一些相关知识。 一.ArrayList的底层数据结构 ArrayList底层是使用一个Object[]数组来存储数据的,所以它本质上...

第四单元
2019/01/11
0
0
ArrayList核心源码解析

一、基本方法解析 1、构造器 ArrayList有三种创建方式 ArrayList的底层实现方式为数组,在创建ArrayList时,底层会创建数组对象Object[] 1.1 无参构造器 通过这种方式创建ArrayList,底层对创...

厚简
2018/04/25
0
0

没有更多内容

加载失败,请刷新页面

加载更多

常用网络安全命令

常用网络安全命令 0. 首先打开cmd win+r 1. ipconfig命令 主要功能:显示本地主机IP地址、子网掩码、默认网关、MAC地址等 C:\> ipconfig/all 2.ping命令 主要功能:目标主机的可达性、名称、...

osc_6n4iy0i5
25分钟前
45
0
element-ui 响应式布局-栅格布局

要注意的问题 xs sm md lg xl五个尺寸的默认值均为24,意味着,任何一个尺寸属性不设置,则该尺寸下响应式宽度为24,这与bootstrap不同 尺寸属性可以设为0,则该el-col不显示 不论尺寸属性设...

osc_7ehwx8hw
27分钟前
45
0
初识二进制与软件破解

文章目录 简介 环境和工具 知识铺垫 实验 总结 简介 实验的思路来自《0day安全:软件漏洞技术分析》第一章。此次实验的内容为如何破解一个简单的密码验证功能的exe文件。通过此次实验可以大体...

osc_z3ivsxnp
28分钟前
35
0
【Q&A干货分享】敲重点,企业必须关注的等保灵魂20问

随着国内疫情防控取得积极成效,企业逐步复工复产,等保合规也重新提上重要日程。自去年12月1日,我国《信息安全等级保护管理办法》正式进入2.0时代,但目前传统的等保安全产品,市面上产品繁...

osc_1ajf1srl
29分钟前
31
0
大众点评字体反爬解析

有关大众点评字体反爬的解析 前几天收到一条私信是有关大众点评的字体反爬的问题,经过分析来此跟大家分享一下解决这个反爬的方法。 1.我们随便打开大众点评一个商家的网页,如下图 2.右键点...

osc_cgllnrkd
30分钟前
91
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部