`
lixusign
  • 浏览: 15135 次
  • 性别: Icon_minigender_1
  • 来自: 广州
社区版块
存档分类
最新评论

ArrayList的elementData声明为transient,为什么还可以序列化?<转>

阅读更多
private transient E[] elementData; 
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方法,仅仅系列化已经存放的数据。
分享到:
评论
1 楼 3111170029 2013-09-06  
你这段  解释了  transient,但却没有解释 transient 后Arraylist 存到文件,再读取为啥依然成功(即transient后的数组依然能够序列化),我同样对数组做了测试我,我发现声明为transient 的数组 依然可以 序列化和反序列化,问题是不是就变成了:“


数组无论是否声明为:transient,都是可以序列化。反序列化的”?

不知道 你这个问题最后解决没?

相关推荐

    C#编程经验技巧宝典

    98&lt;br&gt;&lt;br&gt;0153 如何自定义数字小数点左边分组位数 98&lt;br&gt;&lt;br&gt;0154 格式化输入数据为货币格式 99&lt;br&gt;&lt;br&gt;0155 如何计算两个整数的乘积 99&lt;br&gt;&lt;br&gt;0156 如何将二进制数转换为十进制数 100&lt;br&gt;&lt;br&gt;0157 如何...

    JSP+购物车源代码

    ArrayList&lt;Shop&gt; list = (ArrayList&lt;Shop&gt;)session.getAttribute(ISysConstans.CARNAME); if(list!=null){ for(int i=0;i&lt;list.size();i++){ Shop s = list.get(i); float sum = s....

    struts 标签 logic:iterate使用 logic:iterate

    DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"&gt;&lt;br&gt;&lt;html&gt;&lt;br&gt; &lt;head&gt;&lt;br&gt; &lt;/head&gt;&lt;br&gt; &lt;body&gt;&lt;br&gt; &lt;table&gt;&lt;br&gt; &lt;tr&gt;&lt;br&gt; &lt;td&gt;&lt;%@ include file="../menu.txt"%&gt;&lt;br&gt; &lt;/td&gt;&lt;br&gt; &lt;/tr&gt;...

    .net 各种实用方法

    &lt;summary&gt;拼接DataGridView,返回ArrayList 数组&lt;/summary&gt; &lt;param name="dgv" /&gt; &lt;returns /&gt; &lt;remarks /&gt; &lt;/member&gt; - &lt;member name="M:Pic_Chart_Load.UpLoad_data_Insert.Return_Arr_OneS_data_by_...

    Java测试题2答案

    &lt;br&gt; }&lt;br&gt;}&lt;br&gt;&lt;br&gt;答案::填空第1题&lt;br&gt;x=10,a=3,b=4,c=5&lt;br&gt;填空第2题&lt;br&gt;java.util&lt;br&gt;填空第3题&lt;br&gt;(public )(static )(void)(main)(String args[])&lt;br&gt;填空第4题&lt;br&gt;1&lt;br&gt;填空第5题&lt;br&gt;

    asp.net技术内幕(1)

    第一部分 使用ASP.NET Web表单&lt;br&gt;&lt;br&gt;第1章 建立ASP.NET页面 &lt;br&gt;&lt;br&gt;1.1 ASP.NET和.NET框架 &lt;br&gt;1.1.1 .NET框架类库 &lt;br&gt;1.1.2 理解名称空间 &lt;br&gt;1.1.3 标准的ASP.NET名称空间 &lt;br&gt;1.1.4 与.NET框架兼容的语言 &lt;br...

    asp.net技术内幕(2)

    第一部分 使用ASP.NET Web表单&lt;br&gt;&lt;br&gt;第1章 建立ASP.NET页面 &lt;br&gt;&lt;br&gt;1.1 ASP.NET和.NET框架 &lt;br&gt;1.1.1 .NET框架类库 &lt;br&gt;1.1.2 理解名称空间 &lt;br&gt;1.1.3 标准的ASP.NET名称空间 &lt;br&gt;1.1.4 与.NET框架兼容的语言 &lt;br...

    asp.net技术内幕(5)

    第一部分 使用ASP.NET Web表单&lt;br&gt;&lt;br&gt;第1章 建立ASP.NET页面 &lt;br&gt;&lt;br&gt;1.1 ASP.NET和.NET框架 &lt;br&gt;1.1.1 .NET框架类库 &lt;br&gt;1.1.2 理解名称空间 &lt;br&gt;1.1.3 标准的ASP.NET名称空间 &lt;br&gt;1.1.4 与.NET框架兼容的语言 &lt;br...

    asp.net技术内幕(4)

    第一部分 使用ASP.NET Web表单&lt;br&gt;&lt;br&gt;第1章 建立ASP.NET页面 &lt;br&gt;&lt;br&gt;1.1 ASP.NET和.NET框架 &lt;br&gt;1.1.1 .NET框架类库 &lt;br&gt;1.1.2 理解名称空间 &lt;br&gt;1.1.3 标准的ASP.NET名称空间 &lt;br&gt;1.1.4 与.NET框架兼容的语言 &lt;br...

    asp.net技术内幕(3)

    第一部分 使用ASP.NET Web表单&lt;br&gt;&lt;br&gt;第1章 建立ASP.NET页面 &lt;br&gt;&lt;br&gt;1.1 ASP.NET和.NET框架 &lt;br&gt;1.1.1 .NET框架类库 &lt;br&gt;1.1.2 理解名称空间 &lt;br&gt;1.1.3 标准的ASP.NET名称空间 &lt;br&gt;1.1.4 与.NET框架兼容的语言 &lt;br...

    个人博客jsp代码

    &lt;%@ page import="java.util.ArrayList" %&gt; &lt;%@ page import="com.yxq.valuebean.ArticleTypeBean" %&gt; &lt;% ArrayList typelist=(ArrayList)session.getAttribute("artTypeList"); %&gt; &lt;html&gt; &lt;head&gt; &lt;title&gt;博客后台-...

    购物车代码

    ArrayList&lt;Goods&gt; goods = db.Search(goodsname); int count = 0; Goods goods1 = null; for (; count &lt; goods.size(); count++) { goods1 = goods.get(count); out.println("&lt;tr&gt;"); out....

    JNI与C++数据类型传递示例(包括ArrayList对象、ArrayList嵌套返回)

    一个C++(Ubuntu16.04+QT5.9.1)通过JNI,调用JAVA类及方法的示例。通过JNI传递和返回多种类型的参数,boolean ,int,String,ArrayList&lt;string&gt;,ArrayList嵌套ArrayList&lt;ArrayList&lt;String&gt;&gt;等。

    Java中List<? extends T>与List<? super T>的区别(值得珍藏)

    这里的 &lt;T&gt; 表示泛型,T 表示泛型中装载的类型为T类型,等到需要的时候,我们可以具体这个 T。我们在使用动态数组实现 ArrayList 的时候,如果希望这个 ArrayList 不仅仅支持一个类型的话,我们可以给这个 ArrayList...

    Struts2实现分页

    ArrayList&lt;Users&gt; list; UserService service; Users user; Pager page=new Pager(); public Pager getPage() { return page; } public void setPage(Pager page) { this.page = page; } public ...

    Java JDK实例宝典

    &lt;br&gt;第1章 Java基础 &lt;br&gt;1.1 转换基本数据类型 &lt;br&gt;1.2 Java的运算符 &lt;br&gt;1.3 控制程序的流程 &lt;br&gt;1.4 计算阶乘 &lt;br&gt;1.5 实现命令行程序 &lt;br&gt;第2章 Java面向对象程序设计 &lt;br&gt;2. 1 复数类 &lt;br&gt;2. 2 equals.chashCode...

    intent传递ArrayList&lt;T&gt;

    intent 传递 ArrayList&lt;T&gt;

    arraylist 和 list<T> 效率对比

    Arraylist 和 List&lt;T&gt; 在使用的效率是不一样的,选择不同的集合 能使项目的性能有很大的提高!

    ASP.net技术内幕

    &lt;br/&gt;2.3 在控件上进行格式化 &lt;br/&gt;2.3.1 基本Web控件属性 &lt;br/&gt;2.3.2 在Web控件上应用样式 &lt;br/&gt;2.4 小结 &lt;br/&gt;&lt;br/&gt;第3章 用检验控件执行表单的检验 &lt;br/&gt;&lt;br/&gt;3.1 使用客户端检验 &lt;br/&gt;3.1.1 配置客户端检验 &lt;br/...

    Java Oracle分页处理

    List&lt;PageBean&gt; list = new ArrayList&lt;PageBean&gt;(); newgetResouce newgetresouce = new newgetResouce(); //通过显示页面传递一个pagetype对象和PaginationBean对象 Page page = new Page(request....

Global site tag (gtag.js) - Google Analytics