ArrayList序列化
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序列化的更多相关文章
- 专题二、ArrayList序列化技术细节详解
一.绪论 所谓的JAVA序列化与反序列化,序列化就是将JAVA 对象以一种的形式保持,比如存放到硬盘,或是用于传输.反序列化是序列化的一个逆过程. JAVA规定被序列化的对象必须实现java.io.S ...
- Java中ArrayList源码分析
一.简介 ArrayList是一个数组队列,相当于动态数组.每个ArrayList实例都有自己的容量,该容量至少和所存储数据的个数一样大小,在每次添加数据时,它会使用ensureCapacity()保 ...
- 深入分析Java的序列化与反序列化
序列化是一种对象持久化的手段.普遍应用在网络传输.RMI等场景中.本文通过分析ArrayList的序列化来介绍Java序列化的相关内容.主要涉及到以下几个问题: 怎么实现Java的序列化 为什么实现了 ...
- Java基础之数组序列化、反序列化 小发现(不知道 是不是有问题)
结论: 数组,无论是否声明为transient,都是可以序列化.反序列化的. 测试情况如下: 1.两种类型的数组:int .String: 2 声明为transient 或者不做任何修饰:. 3. ...
- Java 序列化 对象序列化和反序列化
Java 序列化 对象序列化和反序列化 @author ixenos 对象序列化是什么 1.对象序列化就是把一个对象的状态转化成一个字节流. 我们可以把这样的字节流存储为一个文件,作为对这个对象的复制 ...
- java基础( 九)-----深入分析Java的序列化与反序列化
序列化是一种对象持久化的手段.普遍应用在网络传输.RMI等场景中.本文通过分析ArrayList的序列化来介绍Java序列化的相关内容.主要涉及到以下几个问题: 怎么实现Java的序列化 为什么实现了 ...
- Java基础18:Java序列化与反序列化
更多内容请关注微信公众号[Java技术江湖] 这是一位阿里 Java 工程师的技术小站,作者黄小斜,专注 Java 相关技术:SSM.SpringBoot.MySQL.分布式.中间件.集群.Linux ...
- Java对象序列化全面总结
前言 Java允许我们在内存中创建可复用的Java对象,但一般情况下,这些对象的生命周期不会比JVM的生命周期更长.但在现实应用中,可能要求在JVM停止运行之后能够保存(持久化)指定的对象,并在将来重 ...
- Java基础(十一)--Serializable和Externalizable接口实现序列化
序列化在日常开发中经常用到,特别是涉及到网络传输的时候,例如调用第三方接口,通过一个约定好的实体进行传输,这时你必须实现序列 化,这些都是大家都了解的内容,所以文章也会讲一下序列化的高级内容. 序列化 ...
随机推荐
- WebApp与Native App有何区别
转:http://blog.sina.com.cn/s/blog_5f2df1e401018hjj.html 今天看的一篇关于html5的Web App与Native App的技术分析,真的很棒分享一 ...
- ubuntu 用aptitude代替apt-get处理依赖性问题
aptitude 与 apt-get 一样,是 Debian 及其衍生系统中功能极其强大的包管理工具.与 apt-get 不同的是,aptitude 在处理依赖问题上更佳一些.举例来说,aptitud ...
- eclipse安装maven时候如果conf文件夹中有setting文件则会以这个文件为主,如果自己设置了user的配置文件则会无效
eclipse安装maven时候如果conf文件夹中有setting文件则会以这个文件为主,如果自己设置了user的配置文件则会无效
- 使用私钥.pem和SecureCRT登陆linux系统
将密钥上传到一台自己的linux主机,下面举例文件名为 key.pemchmod 600 key.pem改写密钥格式为 OpenSSH,如果询问passphrase可以留空(直接回车)ssh-keyg ...
- nginx expires配置
配置expiresexpires起到控制页面缓存的作用,合理的配置expires可以减少很多服务器的请求要配置expires,可以在http段中或者server段中或者location段中加入 1 ...
- 4G厂商版《出师表》
转载:http://mp.weixin.qq.com/s?__biz=MzAwNDAyODM0NA==&mid=408013599&idx=1&sn=70cd33d037604 ...
- android中SimpleCursorAdapter _id错误的问题
作为一个android新手,在绑定数据的时候是这样的 ListView listview=(ListView)this.findViewById(R.id.listView1); XJDal xj=n ...
- jmeter聚合报告导出时乱码的解决
在使用jmeter性能测试时,聚合报告导出后使用excel打开时是乱码,查看相关文件后是编码的问题,解决方法如下: 1.现象: 用excel打开变成这种乱码无法看清 2.解决: 先使用记事本打开后,选 ...
- nginx 开机自动启动
接下来聊一聊nginx的开机自启吧 看了看都是用脚本启动的,我也就不扯啥犊子了,都是前人经验 我的操作系统是centos 7 nginx版本是1.10.3 首先看一下自己的nginx配置 我的是 ./ ...
- ABP之仓储
一.仓储的简单介绍 仓储(Repository):这是属于领域层的重要组成部分,它的作用就是完成和数据库的交互工作,仓储里封装了很多操作数据库的方法.所以说仓储是数据映射层和领域层的交互中介.ABP针 ...