What is the significance of the transient keyword in Java? If you know the answer, good! you are a person who uses this a lot or a person who has read this very recently. If this seems like a word from a half remembered dream, well don’t worry you have company. I was and am will be confused if you asked me about this in an hour. It is one of those things that I learnt but never had to use it – mainly because I never worked on code that required me to worry about how my objects were serialized. I could delegate that to the libraries.

This post is an attempt to explain what transient is (which most people should know) and an example of how it is used, using the most abused class of my daily work – thejava.util.HashMap class.

What is transient?

The transient keyword in Java is used on class variables and is used to indicate to the runtime that this variable should not be considered while serializing the object is being written to abyte stream. To put it in simpler words, if an object is being written to a byte stream then all transient variables will be ignored.

Lets think about this for a moment. Lets say you have a class that looked like this

public class Bean{

private int a=5;

private transient int b=6;

}

If you were creating an instance of this class and then writing it to a byte stream – a file or a socket, then when serializing this class, the variable ‘a’ will be sent but ‘b’ will be ignored. When you reconstruct this class on the other end, then ‘b’ will be reverted back to the initial default value. So lets say you had some code that updated the value of b to 10 before serializing the object, then when you reconstruct it, the value of b will be 6.

Why would you not want fields to be preserved?

Why would you not want some of the fields in an object to be preserved between storing and retrieving the object? If a field represented a value like a persons name or a amount or some such parameter which has some significance and changing it will impact the application state, then you would definitely want to preserve it. But do you have parameters that you can afford to lose?

Lets say you have a flag that indicates whether the object was modified or not – this is typical in ORM libraries that want to track whether a bean was modified after you retrieved it from the database. The value of the flag that indicates whether the object was modified or not is significant only until the change to the object is saved somewhere and the object is now again clean. So such a flag, lets call it the dirty indicator, is a field that gets reset once it is saved.

If this object was being written to a database to save it, like in an ORM, or written to a file or sent over a socket, then once that is done, then the flag is not needed. Also any code that retrieves the object next time, will expect the flag to be set to the default value which is false for a new instance. So this is a good case to use  transient variable. Set the flag to true while the object is in memory and while writing it to a file, ignore the field. When you read the file again, the field is read a false, which is true because you haven’t yet changed the field.

Do we ever want to use transient for fields that are not reset and need to be preserved?

The answer is yes. And now we will proceed to understand why.

Lets say you have a bean class, like the one I showed above. When this is sent over a socket for example, Java serializes this to a stream of bytes in such a way that it can reconstruct the object on the other end. In order to do this it sends information like -

  • The class name
  • The field names
  • The field values and the lengths

Based on the class name, the JVM on the other end instantiates an object and sets all the values on the respective fields. Since you are sending all the field names and values, it will take a good amount of memory to hold this. If the size of the serialized byte array is larger then it will take more time to send this over the socket and it will take more time to reconstruct it. It will also consume more bandwidth.

There are applications where spending time sending large blocks of data is expensive – so you want to minimize the amount of space occupied by serialized objects and also the time taken to serialize and de-serialize objects. You will write custom code to serialize your objects by writing writeObject(ObjectOutputStream) and readObject(ObjectInputStream) methods.

When you do this, you should mark all your fields as transient and then write them on your own to the object output stream. You can read them back in the same order and reconstruct the object.

Another case is for collections where you store data in an indexed fashion and the index will change when you de-serialize the object – in this case too you will want to mark things as transient and reconstruct them on your own.

So how does a hash map use transients?

There is no good reason why I chose hash map as an example other than the fact that I am most familiar with this and have flogged this to death by using it a lot.

If you look at the source code of java.util.HashMap(http://www.docjar.com/html/api/java/util/HashMap.java.html), you will see that the data that you put in is stored in a array of Entry<K,V> objects. This array is a transient variable called table. There is a table size which is transient too, and there are a bunch of other non-transient and transient variables.

Why is the table a transient? If you look at the code, you will see that for every key that you put in , the class creates a hash code, and using the length of the array (default 16 at start up) it determines the index of the key in the array as

index = hash & (length -1)

Where hash is the return value of Object.hashCode().

There are two important things here – hashCode() does not return the same value for two instances of the same class. And, if a key is not stored in the correct index as per the hash, then it is more expensive to retrieve it. In fact, if you thin about it, if you created hash code on one computer and put the key at a particular index, and then on a different PC calculated the hash code and index, it will return a different value. If you serialized the table as is and reconstructed it, then you will be referring to the wrong index!

So, when a hash map is serialized, it means that the hash index, and hence the ordering of the table is no longer valid and should not be preserved.

For this reason, HashMap implements the writeObject and readObject methods. These still let the non transient fields to get serialized as they would normally do, but they wrote the key value pairs at the end of the byte array one after the other. When reading back, they let the non transient variables to be handled by Java default de-serialization logic and then read the key value pairs one by one.

For each key the hash and the index is calculated again and is inserted to the correct position in the table so that it can be retrieved again without any error.

Conclusion

Although we have not touched upon all uses of transient, we have seen a very good example usage of this in a core Java class.

ref from:http://supercoderz.in/2012/10/02/understanding-transient-variables-in-java-and-how-they-are-practically-used-in-hashmap/

Understanding transient variables in Java and how they are practically used in HashMap---reference的更多相关文章

  1. Life Cycle of Thread – Understanding Thread States in Java

    Life Cycle of Thread – Understanding Thread States in Java 深入理解java线程生命周期. Understanding Life Cycle ...

  2. 【JDK1.8】 Java小白的源码学习系列:HashMap

    目录 Java小白的源码学习系列:HashMap 官方文档解读 基本数据结构 基本源码解读 基本成员变量 构造器 巧妙的tableSizeFor put方法 巧妙的hash方法 JDK1.8的putV ...

  3. Java集合专题总结(1):HashMap 和 HashTable 源码学习和面试总结

    2017年的秋招彻底结束了,感觉Java上面的最常见的集合相关的问题就是hash--系列和一些常用并发集合和队列,堆等结合算法一起考察,不完全统计,本人经历:先后百度.唯品会.58同城.新浪微博.趣分 ...

  4. 如何在JAVA中实现一个固定最大size的hashMap

    如何在JAVA中实现一个固定最大size的hashMap 利用LinkedHashMap的removeEldestEntry方法,重载此方法使得这个map可以增长到最大size,之后每插入一条新的记录 ...

  5. Java中最常用的集合类框架之 HashMap

    一.HashMap的概述 HashMap可以说是Java中最常用的集合类框架之一,是Java语言中非常典型的数据结构.      HashMap是基于哈希表的Map接口实现的,此实现提供所有可选的映射 ...

  6. Java 集合源码分析(一)HashMap

    目录 Java 集合源码分析(一)HashMap 1. 概要 2. JDK 7 的 HashMap 3. JDK 1.8 的 HashMap 4. Hashtable 5. JDK 1.7 的 Con ...

  7. Java集合源码学习(四)HashMap分析

    ArrayList.LinkedList和HashMap的源码是一起看的,横向对比吧,感觉对这三种数据结构的理解加深了很多. >>数组.链表和哈希表结构 数据结构中有数组和链表来实现对数据 ...

  8. Java集合源代码剖析(二)【HashMap、Hashtable】

    HashMap源代码剖析 ; // 最大容量(必须是2的幂且小于2的30次方.传入容量过大将被这个值替换) static final int MAXIMUM_CAPACITY = 1 << ...

  9. Java集合源码分析(四)HashMap

    一.HashMap简介 1.1.HashMap概述 HashMap是基于哈希表的Map接口实现的,它存储的是内容是键值对<key,value>映射.此类不保证映射的顺序,假定哈希函数将元素 ...

随机推荐

  1. MFC 状态栏相关使用(CStatusBar & CStatusBarCtrl)

    原文:MFC 状态栏相关使用(CStatusBar & CStatusBarCtrl),沙漠紫风铃 本文介绍了MFC中和状态栏相关的用法: 在MFC的的单文档应用中,在建好应用程序之后,CMa ...

  2. Hbase学习笔记(安装和基础知识及操作)

    1.Hbase简介 1.面向列的分布式数据库 2. 以HDFS作为文件系统 3. 利用MapReduce处理Hbase中海量数据 4. ZookKeeper作为协调工具 5. sqoop提供Hbase ...

  3. 访问WEB-INF目录中的JSP文件

    方法1:本来WEB-INF中的jsp就是无法通过地址栏访问的.所以安全.如果说你要访问这个文件夹中的jsp文件需要在项目的web.xml文件中去配置servlet格式差不多的配置就ok了.如下: 访问 ...

  4. Loader for loading embedded assemblies z

    using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Ref ...

  5. [Irving]SqlServer 标量函数 详解【转】

    --创建用户定义函数.这是一个已保存 Transact-SQL 或公共语言运行时 (CLR) 例程,--该例程可返回一个值.用户定义函数不能用于执行修改数据库状态的操作.--与系统函数一样,用户定义函 ...

  6. 那些年一起踩过的坑 — Date类型序列化的问题

      坑在哪里?        序列化 和 反序列化 的时候对Date字段的格式设置不一致        例如:将Java bean序列化成Json string的时候 格式为 yyyy-MM-dd 解 ...

  7. 关于.jar的文件在cmd中无法连接数据库的问题

    我使用一个.jar的文件,想在cmd中以“java -jar *.jar”的格式运行,方便system.println()一些信息,该jar包中包含数据库连接内容,在我关闭comodo防火墙和wind ...

  8. 设计原则 Design Principle

    Design Principle设计原则 最近由于碰到要参与设计一个音频处理系统,有人提议用一个大的全局变量结构体来做状态信息交流的地方,引起了我对设计一个系统的思考,于是找到了如下资料,当然,关于这 ...

  9. ubuntu启用root用户

    在安装Ubuntu时系统会提示你创建一个用户,但是该用户不具备ROOT权限.但是此时系统是有root用户的,root密码是随机的,如果你想使用root用户需要更改root密码.用你安装系统时创建的用户 ...

  10. CI支持各种文件上传-文件类型(Linux + window)

    $mimes = array( 'hqx' => 'application/mac-binhex40', 'cpt' => 'application/mac-compactpro', 'c ...