Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/335.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java字符串真的是不可变的吗?_Java - Fatal编程技术网

Java字符串真的是不可变的吗?

Java字符串真的是不可变的吗?,java,Java,在String source中,看起来只有在至少调用了一次方法public int hashCode()时才设置哈希代码值(private int hashCode)。这意味着一个不同的国家。但是在下面的示例中是否会设置哈希代码: String s = "ABC"; ? 意志 后续比较性能的帮助?不可变意味着,从外部角度来看,对象的值不能更改 如果正在缓存hashCode,则在第一次hashCode调用后,对象的内部状态可能不同。但是该调用是只读的,并且您无法更改对象在外部世界中的显示值 换

在String source中,看起来只有在至少调用了一次方法public int hashCode()时才设置哈希代码值(private int 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
    因此:

  • 字符串是不可变的,不能更改其值。您只能创建一个新字符串
  • 首次使用String.hashcode()时计算字符串hashcode。以后的调用返回预先计算的值:
  • 是的,它会更快。如果调用.hashCode(),则在一次性计算hachcode的一小段时间内,后续比较会更快。问题是这是否是实质性的。做你自己的基准测试
    .看看我的答案。调用一个方法的额外时间怎么可能更快呢?总时间显然是相同的,但随后的比较会稍微快一点(对于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;
    }