这个问题在这里已经有答案了:
为什么在hashmap.keyset()中声明局部变量ks[重复](2个答案)
上个月关门了。
mac os上的jdk 8,查看hashmap.java中的以下代码:
public Set<K> keySet() {
Set<K> ks = keySet;
if (ks == null) {
ks = new KeySet();
keySet = ks;
}
return ks;
}
对返回的ks的任何更改都将反映在keyset中,因为它们总是指向相同的基础集,如果这是真的,是否可以写成:
public Set<K> keySet() {
if (keySet == null) {
keySet = new KeySet();
}
return keySet;
}
这两个代码段的行为是否相同?
如果是,为什么 HashMap
使用第一个变量而不是第二个变量?
2条答案
按热度按时间lymnna711#
缓存到局部变量是为了提高性能。生成的字节码更小,字段被读取一次,因此缓存丢失可能只发生一次,以及其他一些事情。
这是一个相当高级的优化,应该只在非常频繁运行的代码段上执行。之所以在这里使用,很可能是因为
HashMap
是用Java1.2编写的,当时jit非常基本,因此类似的东西有相当大的影响。在这种情况下,这样做也是为了支持多线程访问。
HashMap
不是同步的,但是如果以后不修改它,可以通过安全发布共享。如果两个线程同时执行该方法,则可能会发生争用情况:第一次读入if(keySet == null)
无法读取另一个线程写入的较新值,而第二个线程已读入return keySet;
读老一点的(null
)价值观。使用局部变量可以确保if
以及return
非空时使用相同的引用。所以它再也回不来了null
.yfwxisqw2#
正如@fransesco所指出的,局部变量只保存为优化。在某些情况下,它还可以避免创建新对象。
该实现不在内部存储任何状态,而是在底层hashmap上操作,所有操作和对集合的更改都将按照java文档进行
不允许add和addall(抛出unsupportedoperationexception)
remove、retainall都需要修改基础Map
供参考
所有平台的行为都是一样的,不仅仅是mac