Inq*_*ive 21 java string immutability
我正在阅读Joshua Bloch撰写的有效Java第15项.在第15项中谈到"最小化可变性"时,他提到了使对象不可变的五条规则.其中之一就是让所有领域都是最终的.这是规则:
使所有字段成为最终字段:这清楚地以系统强制执行的方式表达您的意图.此外,如果对新创建的实例的引用在没有同步的情况下从一个线程传递到另一个线程,则必须确保正确的行为,如内存模型中所述[JLS,17.5; Goetz06 16].
我知道String类是一个不可变类的例子.通过源代码我看到它实际上有一个非最终的哈希实例.
//Cache the hash code for the string
private int hash; // Default to 0
Run Code Online (Sandbox Code Playgroud)
String如何成为不可变的呢?
era*_*ran 26
该评论解释了为什么这不是最终的:
//缓存字符串的哈希码
这是一个缓存.如果您不打电话hashCode,则不会设置它的值.它可以在创建字符串期间设置,但这意味着更长的创建时间,对于您可能不需要的功能(哈希代码).另一方面,每次询问时计算哈希值都是浪费,给字符串是不可变的,哈希码永远不会改变.
有一个非最终字段的事实确实与你引用的定义有些矛盾,但这里它不是对象界面的一部分.它只是一个内部实现细节,它对字符串的可变性没有影响(作为字符容器).
编辑 - 由于受欢迎的需求,完成我的答案:虽然hash不是公共接口的直接部分,但它可能会影响该接口的行为,因为hashCode它返回其值.现在,由于hashCode未同步,hash如果多个线程同时使用该方法,则可能会多次设置.但是,设置的值hash始终是稳定计算的结果,该计算仅依赖于最终字段(value,offset和count).因此,散列的每次计算都会产生完全相同的结果.对于外部用户来说,这就好像hash是计算过一次 - 就像每次计算它一样,因为合同hashCode要求它始终为给定值返回相同的结果.底线,即使hash不是最终的,它的可变性永远不会被外部观察者看到,因此该类可以被认为是不可变的.
String 是不可变的,因为就其用户而言,它永远不会被修改,并且对所有线程看起来总是一样.
hashCode()使用生动的单一检查成语(EJ第71项)hashCode()来计算它,并且它是安全的,因为如果不小心计算了多次,它不会伤害任何人.
使所有字段成为最终是使类不可变的最简单和最简单的方法,但并不是严格要求的.只要所有方法返回相同的东西,无论哪个线程调用它,该类都是不可变的.