7

当心:我不想比较字符是否相等。因为我知道如何使用 String.equals() 方法。这个问题是关于字符串参考的

当我开始学习 String 类及其属性为不变性等时,我正在为 OCA 考试学习。根据我阅读或可能理解的关于字符串池的内容,当创建字符串时,Java 将此对象存储在他们调用的对象上字符串池,如果使用相同的值创建一个新字符串,它将引用字符串池中的字符串,除非我们使用new关键字,因为这会创建一个新的引用,即使两个字符串都包含相同的值。

例如:

String a = "foo";
String b = "foo";
String c = new String("foo");
boolean ab = (a == b); // This return true
boolean ac = (a == c); // This return false

要清楚这段代码的作用是在第一行代码中,它将创建String a = "foo"并将其存储在字符串池中,在第二行代码中,它将创建String b和引用,"foo"因为它已经存在于字符串池中。但是第 3 行将创建这个字符串的新引用,无论它是否已经存在。这是一个关于正在发生的事情的小图形示例: http://cdn.journaldev.com/wp-content/uploads/2012/11/String-Pool-Java1.png

问题出现在以下代码行上。当通过连接创建字符串时,java 是否会做出不同的东西或简单的 == 比较器有另一种行为?

示例 A:

String a = "hello" + " world!";
String b = "hello world!";
boolean compare = (a == b); // This return true

示例 B:

a = "hello";
b = "hel" + "lo";
compare = (a == b); // This return true

示例 C:

a = "Bye";
a += " bye!";
b = "Bye bye!";
compare = (a == b); // This return false

观看代码运行:( http://ideone.com/fdk6KL )

怎么了 ?

编辑

  1. 修复示例 B 的错误:b = 'hel' + 'lo'

  2. 添加有关问题的说明。这不是比较问题,因为我知道问题的使用String.equals()在字符串池的引用上

4

2 回答 2

12

“当通过连接创建字符串时,java 是否会做出不同的东西或简单的 == 比较器有另一种行为?”

不,它不会改变它的行为,会发生什么:

当连接两个字符串文字"a" + "b"时,jvm 连接两个值,然后检查字符串池,然后它意识到该值已经存在于池中,所以它只是简单地将这个引用分配给字符串。现在更详细:

查看下面这个简单程序的编译字节码:

public class Test  {    
    public static void main(String... args) {
        String a = "hello world!";
        String b = "hello" + " world!";
        boolean compare = (a == b);
    }
}

简单的程序

首先,JVM 加载字符串“hello world!”,然后将其推送到字符串池(在这种情况下),然后将其加载到堆栈中(ldc = 加载常量)[参见图像中的第 1 点]

然后它将在池中创建的引用分配给局部变量 (astore_1) [参见图像中的第 2 点]

请注意,在字符串池中为此文字创建的引用是 #2 [参见图像中的第 3 点]

下一个操作大致相同:in 连接字符串,将其推送到运行时常量池(在本例中为字符串池),但随后它意识到已经存在具有相同内容的文字,因此它使用此引用 (#2) 和分配给局部变量(astore_2)。

因此,当您这样做时 (a == b) 为,因为它们都引用了字符串池 #2,即“hello world!”。

您的示例 C 有点不同,因为您使用的是 += 运算符,该运算符在编译为字节码时使用 StringBuilder 连接字符串,因此这会创建 StringBuilder Object 的新实例,从而指向不同的引用。(字符串池与对象)

于 2017-05-18T14:36:15.873 回答
1
String a = "ef";
String b = "cd" + a;
        
System.out.println("cdef"==b); // false
        
String c = "cd" + "ef";
        
System.out.println("cdef"==c); // true

当对 String 对象调用intern()方法时,它将尝试在池中查找具有相同字符序列的 String。

如果字符串池已经有一个具有相同值的字符串,则返回池中该字符串的引用,否则将字符串添加到池中,并返回引用。

如果表达式是常量表达式,则字符串连接只会对字符串进行内部处理

"cd" + a // is not a Constant Expression
于 2021-08-30T17:07:32.067 回答