2013-04-13 54 views
5
 String s1 = new String("string"); 
     String s2 = new String("string"); 

     String s3 = "string"; 
     String s4 = "string"; 

     System.out.println(s1 == s2);  //FALSE 
     System.out.println(s2.equals(s1)); //TRUE 

     System.out.println(s3 == s4);  //TRUE 
     System.out.println(s3.equals(s4)); //TRUE 

是什么创造s1s3之间的区别? 请让我知道分配和创建新的String差异

在字符串为什么它把这个两个不同,我们只有String对象即可。 s1和s2具有不同的存储器地址,而s3和s4具有相同的存储器地址。 为什么它的工作原理基于new operator。?

+0

如果你想让你的概念在java中清楚字符串请阅读KathySierra Scjp 6。第六章弦乐在弦乐上有着精彩的解释意味着没有人不能更好地解释她。如果你想要pdf,只需在[email protected]给我发邮件给我。如果别人有兴趣,他们也可以给我发邮件。 –

+0

谢谢,刚刚得到它..... – sunleo

回答

5

代表Java源代码中的字符串文字的String对象会在定义它们的类加载时被添加到共享的String池中。这确保了字符串文字的所有“副本”实际上是相同的对象......即使文字出现在多个类中。这就是为什么s3 == s4true

相比之下,当你在new的String中创建一个不同的新的String对象时。这就是为什么s1 == s2false。 (这是new的基本属性,它保证创建并返回一个新的对象...如果它正常完成。)

但是,无论哪种情况,字符串将具有相同的字符,这就是为什么equals返回true


虽然重要的是要明白是怎么回事时,真正教训是比较Java字符串的正确的方法是使用equals,而不是==

如果您想要安排使用==来测试String对象是否相等,可以使用String.intern方法“实习”它们。然而,你必须一贯地这样做......而且在各方面实习都是一个昂贵的过程......所以这通常不是一个好主意。

+0

为什么实习是一个昂贵的过程? – AmitG

+1

许多因素。 1)有一个哈希表,它使用内存,并在调用'intern'时被探测/更新。 2)每个interned字符串都必须使用弱引用存储在散列表中。这是额外的内存+ GC开销。 3)实习字符串存储在(通常有限的)“permgen”空间中。 GC'ing permgen通常需要完整的GC。 –

+0

很好的解释。我在某处读过,Java 1.7字符串不会进入堆的PermGen区域?真的吗? – AmitG

2

JVM有一个自动优化。除非你专门创建一个新的String对象,而另一个String对象已经有相同的值存在,JVM自动假设一个新的对象不是必须的,并且将一个指针赋给你已经存在的平等String对象。

从本质上讲,当你使用第二个选项,这是发生了什么:

步骤1

第一目标是创建没有问题。

步骤2

在创建第二对象之前,字符串池检查的值。 如果该值当前存在,则不需要创建新对象。它只是返回对String对象的引用。

步骤3

而不是被分配一个新对象,但它被简单地提供给在步骤1中这是为了节约存储器取得的对象的引用。

+1

为什么downvote? – christopher

3

s1是一个新的String对象,它不属于任何合并实例的一部分。 s3是来自池的字符串的一个实例。查找java字符串池。看看String上的相关intern()方法。

这个概念并不是java独有的。其他语言支持String interning。在该相关说明中,汇集常用对象遵循flyweight模式,并不限于字符串。看看Integer.valueOf()。整数也有自己的池。

0

发生这种情况是因为new运算符强制创建一个新的String实例,而在第二种情况下,因为String是一个不可变类,JVM为这两个变量提供了相同的String实例以节省内存。因为没有机会这样的对象之一会改变,导致第二个改变(不可改变,记得吗?)这是好的。