今天同事问到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方法,仅仅系列化已经存放的数据。
分享到:
相关推荐
主要为大家详细介绍了Java的序列化与反序列化,序列化是一种对象持久化的手段。普遍应用在网络传输、RMI等场景中。本文通过分析ArrayList的序列化来介绍Java序列化的相关内容,感兴趣的小伙伴们可以参考一下
Doge序列化对象表示法( )的完整,零依赖Java实现。 支持序列化和解析。 正确地将所有数字从和转换为八进制。 一些代码使用名称,以使Shiba Inu狗更容易理解该代码。 用法 public static class DogeExample { ...
【大厂面试题总结】JavaSE面试题总结详细教程: 目录: 递归算法之输出某个目录下所有文件和子目录列表 泛型中extends和super的区别 ...java序列化方式 java中实现多态的机制 string常量池和intern韩雅茹
【大厂面试题总结】JavaSE面试题合集及其答案,基本包括javaSE所有知识点和详细解释 。 JavaSE面试题总结详细教程: 目录: 递归算法之输出某个目录下所有...java序列化方式 java中实现多态的机制 string常量池和intern
序列化和反序列化 继承、封装、多态的实现原理 容器 Java集合类总结 Java集合详解1:一文读懂ArrayList,Vector与Stack使用方法和实现原理 Java集合详解2:Queue和LinkedList Java集合详解3:Iterator,fail-fast机制...
序列化和反序列化 继承封装多态的实现原理 集合类 Java集合类总结 Java集合详解:一文读懂ArrayList,Vector与Stack使用方法和实现原理 Java集合详解:Queue和LinkedList Java集合详解:迭代器,快速失败机制与比较器...
目录: 1、前端 2、JavaSE 3、mysql数据库 4、springboot 5、缓存 更详细目录(子目录): 1、前端目录 ①如何避免CDN为PC端缓存移动端页面 ...15、java序列化方式 16、java中实现多态的机制 17、string常量池和intern
java序列化 JVM加载class文件的原理 双亲委派模型 为什么要自定义类加载器 如何自定义类加载器 什么是GC 内存泄漏和内存溢出 Java的内存模型(JVM的内存划分) JVM内存模型1.7和1.8的区别 如何判断一个对象是否是垃圾...
序列化,Serializable在序列化时使用了反射,从而导致GC的频繁调用。 可见性,原子性,有序性 可见性volatile,一个线程的修改对另外一个线程是马上可见的。 原子性CAS操作,要么都做要么都不做 有序性synchronized...
【基础】Java序列化与反序列化 27 为什么需要序列化与反序列化 28 如何实现Java序列化与反序列化 28 【基础】String s = new String("xyz");创建了几个字符串对象 30 【基础】接口是否可继承(extends)接口?抽象类...
13.9.1 序列化和反序列化操作345 13.9.2 序列化的版本347 13.1 0随机存取文件流348 13.1 1ZIP文件流350 13.1 2本章练习352 第14章 14.1 抽象窗口工具集(AWT)354 14.1.1 AWT组件和容器354 14.1.2 布局管理器359 14.2 ...
序列化:序列化是将对象转换为容易传输的格式的过程。例如,可以序列化一个对象,然后使用 HTTP 通过 Internet 在客户端和服务器之间传输该对象。在另一端,反序列化将从该流重新构造对象。 5.概述o/r mapping 的...
65. 什么是java序列化,如何实现java序列化? 48 65.1. java序列化、反序列化 48 65.2. 对象的序列化主要有两种用途: 48 65.3. 对象序列化包括如下步骤: 49 65.4. 对象反序列化的步骤如下: 49 66. 反射机制 49 ...
序列化:序列化是将对象转换为容易传输的格式的过程。例如,可以序列化一个对象,然后使用 HTTP 通过 Internet 在客户端和服务器之间传输该对象。在另一端,反序列化将从该流重新构造对象。 5.概述o/r mapping 的原理...
7.4.2 ArrayList和Vector实现类 264 7.4.3 固定长度的List 266 7.5 Queue接口 266 7.5.1 LinkedList实现类 266 7.5.2 PriorityQueue实现类 269 7.6 Map 270 7.6.1 HashMap和Hashtable实现类 271 7.6.2 ...
11、什么是java序列化,如何实现java序列化? 59 12、编写一个程序,将d:\java目录下的所有.java文件复制到d:\jad目录下,并将原来文件的扩展名从.java改为.jad。 60 13、java中有几种类型的流?JDK为每种类型的流...
泛型的序列化问题 .NET 2.0 泛型在实际开发中的一次小应用 C#2.0 Singleton 的实现 .Net Framwork 强类型设计实践 通过反射调用類的方法,屬性,字段,索引器(2種方法) ASP.NET: State Server Gems 完整的动态加载/卸载...
如果仅仅是为了实现这个简单的初衷,为什么一切会那么复杂,我觉的自己可以写一个更简单的东西,它不需要过度设计,只需要看上去更酷一点,更小巧一点,功能更强一点。于是我将自己对分布式的理解融入到这个框架中,...
如果仅仅是为了实现这个简单的初衷,为什么一切会那么复杂,我觉的自己可以写一个更简单的东西,它不需要过度设计,只需要看上去更酷一点,更小巧一点,功能更强一点。于是我将自己对分布式的理解融入到这个框架中,...