31

在下面的代码中,字符串文字的行为非常令人困惑。

我可以理解第 1 行、第 2 行和第 3 行是true,但为什么是第 4 行false

当我打印两者的哈希码时,它们是相同的。

class Hello
{
   public static void main(String[] args)
   {
      String hello = "Hello", lo = "lo";
      System.out.print((Other1.hello == hello) + " ");     //line 1
      System.out.print((Other1.hello == "Hello") + " ");   //line 2
      System.out.print((hello == ("Hel"+"lo")) + " ");       //line 3
      System.out.print((hello == ("Hel"+lo)) + " ");         //line 4
      System.out.println(hello == ("Hel"+lo).intern());      //line 5
      System.out.println(("Hel"+lo).hashCode());   //hashcode is 69609650 (machine depedent)
      System.out.println("Hello".hashCode());       //hashcode is same WHY ??.
   }
}

class Other1 { static String hello = "Hello"; }

我知道==检查引用相等并在池中检查文字。我知道equals()是正确的方法。我想了解这个概念。

我已经检查了这个问题,但没有解释清楚。

我将不胜感激一个完整的解释。

4

11 回答 11

26

每个类型的编译时常量表达式String将被放入字符串池中。

本质上,这意味着:如果编译器可以(轻松)“计算”String而不运行程序的值,那么它将被放入池中(规则比这稍微复杂一些,并且有一些极端情况,请参阅链接以上所有细节)。

对于第 1-3 行中的所有字符串都是如此。

"Hel"+lo不是编译时常量表达式,因为是非常量变量lo

哈希码是相同的,因为String 的 hashCode 仅取决于其内容equals()这是和的合同所要求的hashCode()

于 2013-05-24T06:51:07.600 回答
2

可以通过以下方式创建字符串对象:

String str = new String("abcd");  // Using the new operator 
                                  // str is assigned with "abcd" value at compile time.

String str="abcd";         // Using string literal
                           // str is assigned with "abcd" value at compile time.

String str="ab" + "cd";    // Using string constant expression.
                           // str is assigned with "abcd" value at compile time.
String str1 = "cd";
String str = "ab"+str1;    // Using string expression.
                           // str is assigned with "abcd" value at run time only.

并且 Hashcode 将仅在运行时根据 String 对象的内容计算。

于 2013-05-24T07:29:37.120 回答
2

在运行时通过连接计算的字符串是新创建的,因此是不同的

这是一个阅读链接: http: //docs.oracle.com/javase/specs/jls/se7/html/jls-3.html#jls-3.10.5

于 2013-05-24T06:51:20.197 回答
1

这是因为此实例中的编译器不够聪明,无法计算出它可以烧入相同的字符串文字。

哈希码需要始终为等价的字符串返回相同的值(对其调用 .equals 返回 true),因此将返回相同的结果。

于 2013-05-24T06:49:04.743 回答
0

第 3 行和第 4 行的区别如下。

• 由常量表达式计算的字符串在编译时计算,然后将它们视为文字。

• 在运行时通过连接计算的字符串是新创建的,因此是不同的。

以上参考资料取自 java 规范。如果您需要更多说明,请告诉我。

http://docs.oracle.com/javase/specs/jls/se7/html/jls-3.html#jls-3.10.5

于 2013-05-24T07:18:32.847 回答
0

这是因为下面的代码

("Hel"+lo)) + " "

内部翻译为

new StringBuilder("Helo").append(new String(lo)).append(new String(" ")).toString()

因此,您可以看到在不同的 String 实例的帮助下创建了一个全新的 String 实例。这就是为什么当它们指向堆中不同的内存位置时你会得到错误的原因

于 2013-05-24T06:48:34.620 回答
0

hashCode 与对象引用没有任何关系(== 检查是一个引用比较器)。可能有 2 个对象,其中 hashCode 返回相同的值,equals 运算符返回 true,但 == 返回 false。这是当它们是 2 个不同的对象,但具有相同的值时。

我相信第 4 行返回 false 的原因是它是在运行时计算的值,因此是一个不同的字符串实例,具有不同的引用。

于 2013-05-24T06:50:34.427 回答
0

如您所知...这只是因为引用...当字符串来自池时,它将具有相同的引用...但是当您进行操作时,会生成具有新引用的新字符串...

您可以查看此链接以了解池化概念

于 2013-05-24T06:45:24.217 回答
0

String literals are saved in a special memory, if they are exactly the same, they are pointed to the same map of memory. If you don't create a literal String, a new object will be created so it won't point to that memory so the reference won't be the same.

The intern() method tells the virtual machine to put it into that shared, string literals map of memory so next time you do that literal, it'll search there and point it.

于 2013-05-24T06:52:44.507 回答
0

System.identityHashCode()将由默认方法返回hashCode(),这通常通过将对象的内部地址转换为整数来实现。

于 2017-08-31T07:44:50.357 回答
0

终于知道答案了!

阅读 Java SE 8 规范第 15.21.3 节参考相等运算符 == 和 != ( http://docs.oracle.com/javase/specs/jls/se8/html/jls-15.html#jls-15.21.3 )

虽然 == 可用于比较 String 类型的引用,但这样的相等性测试确定两个操作数是否引用相同的 String 对象。

如果操作数是不同的 String 对象,则结果为false ,即使它们包含相同的字符序列(第 3.10.5 节)。可以通过方法调用 s.equals(t) 来测试两个字符串 s 和 t 的内容是否相等。

所以下面的代码:

class Test {
    public static void main(String[] args) {
        String hello = "Hello";
        String lo = "lo";
        System.out.println((hello == ("Hel"+lo))); // line 3
    }
}

第 3 行中的表达式 ("Hel"+lo) 返回在运行时通过串联计算的新字符串。

*在运行时通过连接计算的字符串是新创建的,因此是不同的。(http://docs.oracle.com/javase/specs/jls/se8/html/jls-3.html#d5e1634

所以这段代码的结果:

class Test {
    public static void main(String[] args) {
        String hello = "Hello";
        String lo = "lo";
        System.out.println((hello == ("Hel"+lo))); // line 3
    }
}

会导致:

false

因为,

此表达式中的“Hello”对象:

String hello = "Hello";

和 ("Hel"+lo) 此表达式中的对象:

System.out.print((hello == ("Hel"+lo)) + " ");

不同的,虽然:

*它们都包含相同的序列字符,即“Hello”。

*他们都有相同的hashCode。

*hello.equals(("Hel"+lo)) 将返回 true。

于 2015-07-21T15:09:16.993 回答