将实例字段分配给局部变量

joo*_*wan 16 java

这是来自JDK的HashMap类的keySet()方法.为什么作者将字段(keySet)分配给局部变量ks?

public Set<K> keySet() {
    Set<K> ks;
    return (ks = keySet) == null ? (keySet = new KeySet()) : ks;
}
Run Code Online (Sandbox Code Playgroud)

上面和下面有什么区别?这与线程安全有关吗?

public Set<K> keySet() {
    return (keySet == null ? (keySet = new KeySet()) : keySet;
}
Run Code Online (Sandbox Code Playgroud)

Mic*_*dis 9

如果你看一下keySet声明abstract class AbstractMap<K,V>,你会发现它被定义为:

transient volatile Set<K>  keySet;
Run Code Online (Sandbox Code Playgroud)

由于它是易失性的,因此使用局部变量赋值仅读取一次比读取它所提供的其他示例中的两倍便宜.

此外,如果您要keySet直接返回变量,那么所有客户端代码都将处理易失性引用与非易失性引用(即Set<K> ks)

  • 感谢关于volatile字段读取的答案,我没想过.您能解释一下"处理易失性参考与非易失性参考"部分吗? (2认同)

msa*_*ord 8

为了略微扩展迈克尔的答案,我希望确保keySet()方法永远不会返回null,可能除了提供所提到的性能优势之外.

鉴于此代码:

public Set<K> keySet() {
    return (keySet == null ? (keySet = new KeySet()) : keySet;
}
Run Code Online (Sandbox Code Playgroud)

至少在理论上,在多线程代码中,keySet字段可以设置null在第一个read(keySet == null)和第二个read之间,返回它.我没有看过其余的代码,但我认为还有其他地方keySet可能被分配null.这是作为野外问题的结果,还是防御措施对作者来说是一个问题.

实际代码:

public Set<K> keySet() {
    Set<K> ks;
    return (ks = keySet) == null ? (keySet = new KeySet()) : ks;
}
Run Code Online (Sandbox Code Playgroud)

...没有这个问题,因为该字段只读一次.


归档时间:

查看次数:

680 次

最近记录:

6 年,3 月 前