Understanding transient variables in Java and how they are practically used in HashMap---reference
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的更多相关文章
- Life Cycle of Thread – Understanding Thread States in Java
Life Cycle of Thread – Understanding Thread States in Java 深入理解java线程生命周期. Understanding Life Cycle ...
- 【JDK1.8】 Java小白的源码学习系列:HashMap
目录 Java小白的源码学习系列:HashMap 官方文档解读 基本数据结构 基本源码解读 基本成员变量 构造器 巧妙的tableSizeFor put方法 巧妙的hash方法 JDK1.8的putV ...
- Java集合专题总结(1):HashMap 和 HashTable 源码学习和面试总结
2017年的秋招彻底结束了,感觉Java上面的最常见的集合相关的问题就是hash--系列和一些常用并发集合和队列,堆等结合算法一起考察,不完全统计,本人经历:先后百度.唯品会.58同城.新浪微博.趣分 ...
- 如何在JAVA中实现一个固定最大size的hashMap
如何在JAVA中实现一个固定最大size的hashMap 利用LinkedHashMap的removeEldestEntry方法,重载此方法使得这个map可以增长到最大size,之后每插入一条新的记录 ...
- Java中最常用的集合类框架之 HashMap
一.HashMap的概述 HashMap可以说是Java中最常用的集合类框架之一,是Java语言中非常典型的数据结构. HashMap是基于哈希表的Map接口实现的,此实现提供所有可选的映射 ...
- Java 集合源码分析(一)HashMap
目录 Java 集合源码分析(一)HashMap 1. 概要 2. JDK 7 的 HashMap 3. JDK 1.8 的 HashMap 4. Hashtable 5. JDK 1.7 的 Con ...
- Java集合源码学习(四)HashMap分析
ArrayList.LinkedList和HashMap的源码是一起看的,横向对比吧,感觉对这三种数据结构的理解加深了很多. >>数组.链表和哈希表结构 数据结构中有数组和链表来实现对数据 ...
- Java集合源代码剖析(二)【HashMap、Hashtable】
HashMap源代码剖析 ; // 最大容量(必须是2的幂且小于2的30次方.传入容量过大将被这个值替换) static final int MAXIMUM_CAPACITY = 1 << ...
- Java集合源码分析(四)HashMap
一.HashMap简介 1.1.HashMap概述 HashMap是基于哈希表的Map接口实现的,它存储的是内容是键值对<key,value>映射.此类不保证映射的顺序,假定哈希函数将元素 ...
随机推荐
- angularjs filter 详解
系统的学习了一下angularjs,发现angularjs的有些思想根php的模块smarty很像,例如数据绑定,filter.如果对smarty比较熟悉的话,学习angularjs会比较容易一点.这 ...
- Oracle 给表添加主键和使ID自增、触发器、创建结构一样的表
1.关于主键:在建表时指定primary key字句即可:create table test( id number(6) primary key, name varchar2(30));如果是对于已经 ...
- 【转】vnc centos
原文:http://www.cnblogs.com/niocai/archive/2011/11/02/2233332.html 我的CentOS版本是6.0,下述方法在i386和x86_64中均适用 ...
- 【windows核心编程】 第六章 线程基础
Windows核心编程 第六章 线程基础 欢迎转载 转载请注明出处:http://www.cnblogs.com/cuish/p/3145214.html 1. 线程的组成 ① 一个是线程的内核 ...
- 【原】Redis-LRU缓存
Redis高级篇 Redis-LRU缓存 将Redis作为缓存使用时,有时添加新数据时,旧数据是很难被清空的. LRU(Least Recently Used) 近期最少使用算法是常用算法之一. 最大 ...
- js特效第九天
offset家族(获取元素尺寸) offsetWidth得到对象的宽度,自己的,与他人无关 offsetWidth = width+border+padding,不包含margin offsetHei ...
- 初涉C#防止黑客攻击站短
一.同一个IP如果在一分钟内连续发送5个站短可以认为是不正确的,原因有2方面: 1.发站短的页面是有点击按钮,点击按钮后马上按钮会变为不可点击,所以在前端要防止点击一次触发多次的情况 2.发送短信的U ...
- 常规页生命周期(class0620)
常规页声明周期阶段 阶段 说明 页请求 开始 页初始化 加载 验证 回发事件处理 卸载 生命周期事件 页事件 典型使用
- spring框架中一个跟String的trim方法一样的方法
@Test public void testTrimWhitespace() throws Exception { assertEquals(null, StringUtils.trimWhitesp ...
- WIN32不得不会:视频播放器
我愿分享我所有的技术,你可愿意做我的朋友? ----赵大哥 为何要写这篇博客 纯WIN32API打造,自认为对底层的理解略有帮助,和大家分享成果和知识点. 已经实现功能有:打开.播放.关闭功能. 核心 ...