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. enum hack

    关于占用内存的大小,enum类型本身是不占内存的,编译器直接替换.但是enum类型的变量肯定是占内存的. class A{ public: //enum类型本身不占内存 enumEnumTest{ a ...

  2. C# NameValueCollection集合 (转)

    1.NameValueCollection类集合是基于 NameObjectCollectionBase 类. 但与 NameObjectCollectionBase 不同,该类在一个键下存储多个字符 ...

  3. 【Studio】解决格式化时,注释部分没有缩进的问题

    android studio默认代码格式化(默认Ctrl+Alt+L),是让注释从每行最左边开始显示,比如这样: 我个人喜欢注释也要缩进对齐.其实这个需要自己设置,打开studio的设置,依次找 Se ...

  4. Oracle中V$SESSION等各表的字段解释,Oracle官方解释

    一.常用的视图 1.会话相关视图 View Description V$PROCESS Contains information about the currently active processe ...

  5. mysql optimize整理表碎片

    当您的库中删除了大量的数据后,您可能会发现数据文件尺寸并没有减小.这是因为删 除操作后在数据文件中留下碎片所致.optimize table 可以去除删除操作后留下的数据文件碎片,减小文件尺寸,加快未 ...

  6. cadence allegro 封装焊盘编号修改 (引脚编号修改)

    1. 打开dra文件在find里面 off all  然后只点击text 2.点击需要更改的焊盘 3.菜单栏edit - text 4.弹出窗口修改即可 注意: 按照网上的其他操作并没有执行步骤1操作 ...

  7. Java反射机制获取Class文件

    JAVA反射机制是在运行状态中,对于任意一个类(class文件),都能够知道这个类的所有属性和方法:对于任意一个对象,都能够调用它的任意一个方法和属性:这种动态获取的信息以及动态调用对象方法的功能称为 ...

  8. nodeJS删除文件

    var fs = require("fs"); var path = require("path"); deleteFolderRecursive = func ...

  9. ELK之filebeat-redis-logstash-es构架模式

    下载filebeat的rpm包安装filebeat wget https://artifacts.elastic.co/downloads/beats/filebeat/filebeat-6.3.0- ...

  10. codeforces#518 Div2 ABCDE

    A---Birthday http://codeforces.com/contest/1068/problem/A 题意: 有n种硬币,m个人.m个人要给Ivan送硬币,每个人送的硬币都要互不相同但数 ...