ArrayList源代码中的

private transient E[] elementData;  

声明为transient,为什么还可以序列化成功呢?

ArrayList重写了

private void writeObject(java.io.ObjectOutputStream s)
throws java.io.IOException{
int expectedModCount = modCount;
// Write out element count, and any hidden stuff
s.defaultWriteObject(); // Write out array length
s.writeInt(elementData.length); // 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();
}
}

在使用ObjectOutputStream序列化对象时会调用这个writeObject方法。

第二个问题是为什么要声明为transient呢?

在google了下,发现主流说法如下:

ArrayList实现了java.io.Serializable接口,所以ArrayList对象可以序列化到持久存储介质中。ArrayList的主要属性定义如下:

    * private static final long serialVersionUID = 8683452581122892189L;
* private transient Object elementData[];
* private int size; 可以看出serialVersionUID和size都将自动序列化到介质中,但elementData数组对象却定义为transient了。
也就是说 ArrayList中的所有这些元素都不会自动系列化到介质中。为什么要这样实现?因为elementData数组中存储的
“元素”其实仅是对这些元素的一个引用,并不是真正的对象,序列化一个对象的引用是毫无意义的,因为序列化是为了
反序列化,当你反序列化时,这些对象的引用已经不可能指向原来的对象了。所以在这儿需要手工的对ArrayList的元素进
行序列化操作。这就是writeObject()的作用。

果真如此么??????

验证下:

把ArrayList的内容完全copy到一个新类里面,命名为MyArrayList,如下:

public class MyArrayList<E> extends AbstractList<E>
implements List<E>, RandomAccess, Cloneable, java.io.Serializable
{
private static final long serialVersionUID = 8683452581122892189L; /**
* The array buffer into which the elements of the ArrayList are stored.
* The capacity of the ArrayList is the length of this array buffer.
*/
private E[] elementData; 。。。。。。。。 private void writeObject(java.io.ObjectOutputStream s)
throws java.io.IOException{
int expectedModCount = modCount;
// Write out element count, and any hidden stuff
s.defaultWriteObject(); 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 {
// Read in size, and any hidden stuff
s.defaultReadObject();
} }

把transient去掉,write/readObject采用默认方式。

测试下MyArraylist序列化功能:

MyArrayList al = new MyArrayList<String>();
al.add("sssssssssssssssss");
al.add("bbbbbbbbbbbbbbbbbbt");
al.add("gggggggggggggggggg"); ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("D:\\al.tmp"));
oos.writeObject(al); ObjectInputStream ois = new ObjectInputStream(new FileInputStream("D:\\al.tmp")); MyArrayList<String> a = (MyArrayList<String>)ois.readObject();
for(String s: a)
{
System.out.println(s);
}

输出结果为:

sssssssssssssssss
bbbbbbbbbbbbbbbbbbt
gggggggggggggggggg

到此证明:引用序列化无效的说法是错误的,这点在ObjectOutputStream中也有说明。

那是为什么呢?

既然是数组,要序列化到文件中,那就单独测试下数组对象的序列化和反序列化吧

                String[] stra = new String[4];
stra[0] = "mmmmmmmmmm";
stra[2] = "nnnnnnnnnn"; oos = new ObjectOutputStream(new FileOutputStream("D:\\sa.tmp"));
oos.writeObject(stra); ois = new ObjectInputStream(new FileInputStream("D:\\sa.tmp")); String[] str = (String[])ois.readObject();
for(String s: str)
{
System.out.println(s);
}

输出结果为:

mmmmmmmmmm
null
nnnnnnnnnn
null

从输出结果来看,数组序列化时,不管是否有值,都会将整个数组序列化到文件中。

由此可以看出,比较靠谱的原因是:

ArrayList是会开辟多余空间来保存数据的,而系列化和反序列化这些没有存放数据的空间是要消耗更多资源的,所以ArrayList的数组就声明为transient,自己实现write/readObject方法,仅仅系列化已经存放的数据。

http://kakaluyi.iteye.com/blog/870137#

ArrayList序列化的更多相关文章

  1. 专题二、ArrayList序列化技术细节详解

    一.绪论 所谓的JAVA序列化与反序列化,序列化就是将JAVA 对象以一种的形式保持,比如存放到硬盘,或是用于传输.反序列化是序列化的一个逆过程. JAVA规定被序列化的对象必须实现java.io.S ...

  2. Java中ArrayList源码分析

    一.简介 ArrayList是一个数组队列,相当于动态数组.每个ArrayList实例都有自己的容量,该容量至少和所存储数据的个数一样大小,在每次添加数据时,它会使用ensureCapacity()保 ...

  3. 深入分析Java的序列化与反序列化

    序列化是一种对象持久化的手段.普遍应用在网络传输.RMI等场景中.本文通过分析ArrayList的序列化来介绍Java序列化的相关内容.主要涉及到以下几个问题: 怎么实现Java的序列化 为什么实现了 ...

  4. Java基础之数组序列化、反序列化 小发现(不知道 是不是有问题)

    结论:  数组,无论是否声明为transient,都是可以序列化.反序列化的. 测试情况如下: 1.两种类型的数组:int .String: 2 声明为transient  或者不做任何修饰:. 3. ...

  5. Java 序列化 对象序列化和反序列化

    Java 序列化 对象序列化和反序列化 @author ixenos 对象序列化是什么 1.对象序列化就是把一个对象的状态转化成一个字节流. 我们可以把这样的字节流存储为一个文件,作为对这个对象的复制 ...

  6. java基础( 九)-----深入分析Java的序列化与反序列化

    序列化是一种对象持久化的手段.普遍应用在网络传输.RMI等场景中.本文通过分析ArrayList的序列化来介绍Java序列化的相关内容.主要涉及到以下几个问题: 怎么实现Java的序列化 为什么实现了 ...

  7. Java基础18:Java序列化与反序列化

    更多内容请关注微信公众号[Java技术江湖] 这是一位阿里 Java 工程师的技术小站,作者黄小斜,专注 Java 相关技术:SSM.SpringBoot.MySQL.分布式.中间件.集群.Linux ...

  8. Java对象序列化全面总结

    前言 Java允许我们在内存中创建可复用的Java对象,但一般情况下,这些对象的生命周期不会比JVM的生命周期更长.但在现实应用中,可能要求在JVM停止运行之后能够保存(持久化)指定的对象,并在将来重 ...

  9. Java基础(十一)--Serializable和Externalizable接口实现序列化

    序列化在日常开发中经常用到,特别是涉及到网络传输的时候,例如调用第三方接口,通过一个约定好的实体进行传输,这时你必须实现序列 化,这些都是大家都了解的内容,所以文章也会讲一下序列化的高级内容. 序列化 ...

随机推荐

  1. 【cs229-Lecture12】K-means算法

    上课内容: 无监督学习: K-means聚类算法 混合高斯模型 jensen不等式(用于推导出EM算法的一般形式) EM(Expectation Maximization)算法(最大期望算法) K-m ...

  2. python错误 ImportError: No module named setuptools 解决方法[转]

    在python运行过程中出现如下错误: python错误:ImportError: No module named setuptools这句错误提示的表面意思是:没有setuptools的模块,说明p ...

  3. Linux下grep命令查找带有tab(退格)的字符

    需要在日志文件统计删除的主帖,而日志文件是tab(退格)字符隔开的:假设日志文件名叫delete.log. 保存格式和保存的数据如下, 删除日期            帖子类型(11为主帖,12为回帖 ...

  4. Ubuntu 14.04 DNS 配置

    最近得到一个比较好用的DNS,每次重启后都修改DNS配置文件 /etc/resolv.conf 重启就会失效 从网上得知 /etc/resolv.conf中的DNS配置是从/etc/resolvcon ...

  5. 常用的数据整理的JavaScript库

    Lodash.js https://lodash.com/ Underscore.js https://www.html.cn/doc/underscore/

  6. How to Use Postman to Manage and Execute Your APIs

    How to Use Postman to Manage and Execute Your APIs Postman is convenient for executing APIs because ...

  7. Dumb Bones UVA - 10529[多米诺重构]

    Dumb Bones UVA - 10529   来自绿书p176  题意 你试图把一些多米诺骨牌排成直线,然后推倒它们.但是如果你在放骨牌的时候不小心把刚放的骨牌碰倒了,它就会把相临的一串骨牌全都碰 ...

  8. CentOS上传下载查看命令

    之前往CentOS中上传都用ftp软件,这里介绍一种另外的上传下载方式,两个命令轻松搞定.这两个命令目前只针对Xshell和SecureCRT等远程终端软件才支持,并且还会有时间的限制.大概30秒不上 ...

  9. oracle fm格式化

    select to_char(0.56,'FM999,999,990.00' ) from dual 其中 9代表如果存在数字则显示数字,不存在显示空格 其中 0代表如果存在数字则显示数字,不存在则显 ...

  10. Penn Treebank

    NLP中常用的PTB语料库,全名Penn Treebank.Penn Treebank是一个项目的名称,项目目的是对语料进行标注,标注内容包括词性标注以及句法分析. 语料来源为:1989年华尔街日报语 ...