Java字符串真的是不可变的吗?
在String source中,看起来只有在至少调用了一次方法public int hashCode()时才设置哈希代码值(private int hashCode)。这意味着一个不同的国家。但是在下面的示例中是否会设置哈希代码:Java字符串真的是不可变的吗?,java,Java,在String source中,看起来只有在至少调用了一次方法public int hashCode()时才设置哈希代码值(private int hashCode)。这意味着一个不同的国家。但是在下面的示例中是否会设置哈希代码: String s = "ABC"; ? 意志 后续比较性能的帮助?不可变意味着,从外部角度来看,对象的值不能更改 如果正在缓存hashCode,则在第一次hashCode调用后,对象的内部状态可能不同。但是该调用是只读的,并且您无法更改对象在外部世界中的显示值 换
String s = "ABC"; ?
意志
后续比较性能的帮助?不可变意味着,从外部角度来看,对象的值不能更改 如果正在缓存
hashCode
,则在第一次hashCode
调用后,对象的内部状态可能不同。但是该调用是只读的,并且您无法更改对象在外部世界中的显示值
换句话说,它仍然是相同的字符串。从技术上讲字符串已更改。某些内部字段在您第一次调用
hashCode()
时被更改
但由于所有实际原因,字符串是不可变的。哈希代码的值不会因为调用
hashCode()
而改变,它只是在第一次调用之前不会计算。对于字符串的任何使用者,该字符串都是不可变的。这才是最重要的。正如Robert Harvey和Greg所说,出于所有实际目的,字符串对象是不可变的(可以通过反射来更改内容,但这是一种攻击)
在构造之后立即调用hashCode()
理论上可能有助于提高性能。然而,对于所有实际目的而言,这是过早的优化
但是在下面的示例中会设置hashCode吗
没有
[calling hashCode]是否有助于后续的性能比较
假设您指的是对String.equals(Object)
的后续调用,那么答案是“否”。equals
方法不使用字符串的hash
值,无论之前是否计算过该值
如果您指的是对String.hashCode()
的调用,答案是“可能不是”。最多你会得到一个一次性的计算结果,它发生得越早越好。hashCode
方法仍然需要测试每次调用的hash
是否为零
编辑
我认为很明显,不同的JVM供应商实现String.equals的方式不同。例如,@Alex引用的IBM版本使用缓存的hashcode,但Sun的jdk1.6版本没有
由此我们得出结论,任何调用String.hashCode()
以“优化”String.equals
的尝试都将产生依赖于JVM的结果。此外,对于@Alex正在使用的特定IBM JVM,它看起来可能是有益的。。。前提是你对两个字符串都做了
但我仍然认为这是个坏主意。。。除非您从分析中得到明确的证据表明String.equals()
是一个重要的瓶颈
这是实际的String.hashCode()实现:
public int hashCode() {
int h = hash; // hash is a field in String
if (h == 0) {
int off = offset;
char val[] = value;
int len = count;
for (int i = 0; i < len; i++) {
h = 31*h + val[off++];
}
hash = h;
}
return h;
}
public int hashCode(){
int h=hash;//hash是字符串中的字段
如果(h==0){
int off=偏移量;
char val[]=值;
int len=计数;
对于(int i=0;i
因此:
.看看我的答案。调用一个方法的额外时间怎么可能更快呢?总时间显然是相同的,但随后的比较会稍微快一点(对于hashcode的一次性计算,如我所写)。这就是最初的海报所要求的。发问者的意思可能是“在随后的通话中更快,以牺牲设置速度为代价”。他的意思是这样的。但他仍在放慢他的整体计划。那么有什么区别呢?@EJP你假设他的程序是线性的。如果后续调用之间存在显著差异(一个大的“如果”),则可以在其他瓶颈出现时(例如,在等待磁盘访问时)首先进行方法调用。然后,如果稍后在CPU密集的代码区域调用hashCode,则可以获得总体改进。“理论上说,”格伦德莱克,我不明白。调用一个方法两次不能比调用一次快。@EJP不,它不能,但是在程序的某一点上进行较慢的调用,以便在另一点上进行较快的调用,可能会大大缩短时间。这是相当迟钝的,但如果内存中有一百万个对象,它们都将在循环中调用hashCode,在程序等待加载文件时预先填充它们的hashCode,可能会加快循环。不太可能,但可能:)事实上,在构造之后调用hashCode更有可能对性能产生负面影响。第一次调用.hashCode()时,私有字段仍将被填充;实际上,您可能从根本不必计算哈希代码中获益。事实上,在这种特定情况下,优化还远远不够成熟。这是一个有12年历史的巨大应用程序。不幸的是,已知的工作速度不够快。一个字符串和同一个字符串进行了无数次的比较(我自己也会使用整数,但这就是生活)。第二个比较的字符串来自遥远的事务,你可以打赌它里面没有hasCode。这仍然是不成熟的-如果这个字符串被比较了数百万次,第一个字符串是否被比较并不重要
public int hashCode() {
int h = hash; // hash is a field in String
if (h == 0) {
int off = offset;
char val[] = value;
int len = count;
for (int i = 0; i < len; i++) {
h = 31*h + val[off++];
}
hash = h;
}
return h;
}