transient与序列化

今天查看hashmap的源码,看到一个关键词 transient。

序列化
序列化就是一种用来处理对象流的机制,所谓对象流也就是将对象的内容进行流化。可以对流化后的对象进行读写操作,也可将流化后的对象传输于网络之间。序列化是为了解决在对对象流进行读写操作时所引发的问题。
序列化的实现:将需要被序列化的类实现Serializable接口,然后使用一个输出流(如:FileOutputStream)来构造一个ObjectOutputStream(对象流)对象,接着,使用ObjectOutputStream对象的writeObject(Object obj)方法就可以将参数为obj的对象写出(即保存其状态),要恢复的话则用输入流。

transient
修饰实力域,使其从一个类的默认序列化形式中省略(即默认序列化方式不对该字段做写与读 存取操作)

应用场景

  1. 业务需要,不宜做序列化

如银行密码等 信息不希望在网络和磁盘等地方存储,所以可以用 transient 声明,从而保证相应信息无法从磁盘读取。

  1. 默认的序列化方式不适合,采用自定义序列化的方式

例hashMap中对元素的存储。java 7中hashMap元素的存储结构为 表 (table)+ 链(结点构成的链)的存储结构。其中根据hash(key)求的对应元素在table的索引,并将元素插入此索引处的链表。
其中的实例域table 即为 transient

/** 
 * The table, resized as necessary. Length MUST Always be a power of two. 
 */  
transient Entry<K,V>[] table = (Entry<K,V>[]) EMPTY_TABLE; 

那么问题来了,既然table中存储着hashMap中的元素信息,为什么不序列化?

答:不是不序列化,而是不采用默认的序列化。
由于table中元素信息是我们存取关注的,而非table的结构,所以能合理的完成table中所有信息的存取是关键。
鉴于table结构过于复杂(其中的链表结构为Entry 结点构成的链表),若采用默认的序列化方式,会将table的完整结构(包括各链表)镜像一份,如此以来带来一下弊端:
1. 不仅需要消化大量时间遍历table结构
2. 占用较多的存储空间
3. 默认序列化对对象图做递归遍历当表过大时会发生堆栈溢出,所以避免使用默认的序列化方式。
hashMap中采用序列化存储过程中遍历table中元素,并逐一序列化储存。而在序列化读取过程中,根据读出数值还原表结构的方式来完成,从而提高序列化的质量。过程如下:

private void writeObject(java.io.ObjectOutputStream s)  
        throws IOException  
    {  
        // Write out the threshold, loadfactor, and any hidden stuff  
        s.defaultWriteObject();  
         ….  
          //自定义完成table中信息的存储  
        // Write out keys and values (alternating)  
        if (size > 0) {  
            for(Map.Entry<K,V> e : entrySet0()) {  
                s.writeObject(e.getKey());  
                s.writeObject(e.getValue());  
            }  
        }  
    }  

    private static final long serialVersionUID = 362498820763181265L;  

    /** 
     * Reconstitute the {@code HashMap} instance from a stream (i.e., 
     * deserialize it). 
     */  
    private void readObject(java.io.ObjectInputStream s)  
         throws IOException, ClassNotFoundException  
    {  
        // Read in the threshold (ignored), loadfactor, and any hidden stuff  
        s.defaultReadObject();  
        ...  
        //依次读取,并还原表结构  
        // Read the keys and values, and put the mappings in the HashMap  
        for (int i = 0; i < mappings; i++) {  
            K key = (K) s.readObject();  
            V value = (V) s.readObject();  
            putForCreate(key, value);  
        }  
    } 

如此,当自定义中实例域存储机构将复杂,默认序列化方式无法胜任时,可以声明为transient,并自定义完成该字段中信息的序列化。

感谢原作者,文章引用:
http://blog.csdn.net/youxin2012/article/details/50719571

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值