看看java源码中那些引人深思的写法_no.1

案例一:在jdk Hashmap的源码中,有一段如下:

看看java源码中那些引人深思的写法_no.1

相信看过Hashmap源码的人都知道,table其实就是hash桶数组,然后每一个桶后面是链表,对于jdk8,过长的情况下为红黑树。

但是我们今天关注的重点是transient这个关键字,As you know,被transient修饰的字段不能被序列化。

为什么不能被序列化,这个问题跟hashcode有关系。

在回答这个问题之前,我先提出另一个问题,如下:

看看java源码中那些引人深思的写法_no.1

上面这行代码,在不同的jvm里面运行得到的值是一定一样的吗?比如说在你本机window的电脑上和在linux服务器上运行?

答案肯定是不可能都是一样的。

有人误以为默认情况下(即Object中),hashCode返回的就是对象的存储地址,事实上这种看法是不全面的,确实有些JVM在实现时是直接返回对象的存储地址,但是大多时候并不是这样,只能说可能存储地址有一定关联。

看看java源码中那些引人深思的写法_no.1

Object里面的hashCode方法是native的,也就是说他是在jvm里面实现的。而不同的jvm实现的方式又不一样。所以得到在值不可能总是一样的。

 

 回头再来回答我们最初的问题。

如果你使用String作为hashmap的key,假设这里的table可以序列化。

然后将你序列化后的对象传到其他的机器上,反序列化之后,同样的"JAVA"字符串,序列化之前和序列化之后,他的hashcode不一样。

也就是说"JAVA"这个key的entry,原来在table[0]中,反序列化之后,可能不在table[0]中。HashMap的内存结构变了。

还有另一方面的原因:

因为 HashMap 中的存储数据的数组数据成员中,数组还有很多的空间没有被使用,没有被使用到的空间被序列化没有意义。

 

话题到这儿还没有结束!

看看java源码中那些引人深思的写法_no.1

table不能序列化,but,他又实现了Serializable接口。别急,HashMap还是可以序列化的。

看看java源码中那些引人深思的写法_no.1

他重写了writeObject,也就是说HashMap在序列化时不会直接进默认的writeObject(即defaultWriteObject)

看看java源码中那些引人深思的写法_no.1

最终的答案是,HashMap将所有的数据一一取出,然后对他们序列化。