2012-03-14 13 views
52

我有以下几行代码来比较字符串。 str1不等于str2,这是可以理解的,因为它比较了对象引用。但为什么s1等于s2?什么使参考比较(==)适用于Java中的某些字符串?

String s1 = "abc"; 
String s2 = "abc"; 

String str1 = new String("abc"); 
String str2 = new String("abc"); 

if (s1==s2) 
    System.out.println("s1==s2");   
else 
    System.out.println("s1!=s2"); 

if (str1==str2) 
    System.out.println("str1==str2");   
else 
    System.out.println("str1!=str2"); 

if (s1==str1) 
    System.out.println("str1==s1");   
else 
    System.out.println("str1!=s1"); 

输出:

s1==s2 
    str1!=str2 
    str1!=s1 
+12

你尝试搜索SO第一? :( – 2012-03-14 17:44:28

+13

http://stackoverflow.com/questions/7144059/java-string-pool-object-creation,http://stackoverflow.com/questions/4033625/if-compares-references-in-java-why-does -it-evaluate-to-true-with-these-strin,http://stackoverflow.com/questions/6377058/string-reference,http://stackoverflow.com/questions/1903094/java-strings-and-stringpool – 2012-03-14 17:45:56

+1

(我没有关闭这个,因为我还没有发现另一个问题*因为这个焦点*,但我确信它存在) – 2012-03-14 17:49:17

回答

80

的字符串常量池将基本缓存所有的字符串文字,以便它们是相同的物体的下面,这就是为什么你看到你s1==s2来做输出。它基本上是VM中的一种优化,以避免每次声明文字时创建新的字符串对象,这可能会非常快速地变得非常昂贵!用你的str1==str2的例子,你明确地告诉VM创建新的字符串对象,因此它是错误的。

另外,对任何字符串调用intern()方法会将其添加到常量池(并返回它添加到池中的字符串)。但是,除非确定,否则不一定是好主意你正在处理的字符串肯定会被用作常量,否则你可能最终难以追踪内存泄漏。

+2

你打我2秒只给了intern()方法的想法 – 2012-03-14 08:39:25

+6

你打盹你输了。haha j/k。= P – 2012-03-14 13:01:57

+1

+1但也值得注意的是,在常量池中添加大量字符串是一个坏主意,因为它会导致难以检测到的内存泄漏。只对真正用作常量的小数字固定字符串(例如HashMap键)执行此操作,绝对不能用于任意字符串数据。 – mikera 2012-03-14 20:56:43

18

s1和s2是字符串文字。当您创建新的字符串文字时,编译器首先检查是否有任何代表相同的文字出现在字符串池中。如果有一个存在,编译器将返回该文字,否则编译器将创建一个新的文字。

当您创建字符串s2时,编译器会返回字符串s1,因为它已经在之前创建。这就是s1s2相同的原因。这种行为被称为内部

+0

当你说“编译器创建一个新的”时,我有点困惑。 AFAIK,编译器用于创建中间机器代码,并不实际运行(因此创建)内存中的任何对象。你的意思是编译器_replaces_字符串文字吗?请澄清这一点。 – peakit 2012-03-20 18:41:34

+0

我目前没有任何支持文档,但我相信@Chandra Sekhar指的是JIT或Just In Time编译器,而不是javac编译器。 – Robert 2012-03-20 19:39:27

3

在Java中,相同的常量字符串将被重用。因此s1s2指向相同的“abc”对象和s1==s2。但是当您使用new String("abc")时,将创建另一个对象。那么s1 != str1

5

这是由于字符串文字被实施。在这个问题上,Java documentations说:

所有文字字符串和字符串值的常量表达式是 实习

这解释了为什么s1s2是相同的(这两个变量指向实习相同字符串)

0

由于string是在java中不可改变的,所有的string literals缓存的可重用性。

当您使用new()运算符创建String对象时,它总是在堆内存中创建一个新对象。另一方面,如果使用字符串文字语法创建对象,例如“Java”中,如果它已经存在,它可以从字符串池(在Perm gen空间中的一个字符串对象的缓存,现在移到最近的Java版本中的堆空间)返回一个现有的对象。否则,它将创建一个新的字符串对象并放入字符串池以供将来重新使用。

String s1 = new String("java"); 
String s2 = new String("java"); 
String s3 = "java"; 
String s4 = "java"; 

enter image description here

Please refer this link