两个具有相同内容的字符串是否会存储在同一个内存位置?

时间:2013-04-04 07:59:16

标签: java string memory-management

这是我在接受采访时遇到的一个问题。

我有两个字符串定义为

String s1="Java";
String s2="Java";

我的问题是这两个引用是否指向相同的内存位置。通常,当我们创建相同的字符串(没有new关键字)时,内容是否只存储在内存中一次,所有具有相同内容的String对象只是引用相同的位置,而不是冗余地存储字符串“Java”? s1和s2的哈希码是相同的。但是哈希码是否直接依赖于对象的内存位置?

9 个答案:

答案 0 :(得分:23)

组合相同字符串的过程称为“interning”,并且已经被许多语言编译器多年来完成,但并非总是如此。这个问题的答案,特别是由@ GennadyVanin - Novosibirsk扩展,取决于语言和编译器的实现。对于Java,根据Java Language Specification的要求,所有常量字符串都被实现。但这只是常量字符串表达式,并且只有在它们同时编译时才会出现。如果有两个Java字符串在时间和空间上充分分开(例如,编译成单独的JAR文件),它们将不是同一个对象。类似地,动态创建的Java字符串(例如,各种toString()方法的输出)将不会被实现,除非该方法通过String.intern()专门请求它。是的,内部字符串的所有使用都将共享相同的内存位置 - 这是字符串首先被实现的主要原因。

至于其他语言,这是一个更大的问题,但是根据这些答案中的所有信息,我相信你可以在网上研究它。我只想说就如何做到这一点没有普遍的一致意见。

答案 1 :(得分:7)

String s1="Java";
String s2="Java";
My question is whether these two references point to the same memory location  

哑巴引用 §3.10.5 of Java Language Specification

  

字符串文字是对String类实例的引用   (§4.3.1§4.3.3)。

     

此外,字符串文字总是指同一个类的实例   串。这是因为字符串文字 - 或者更一般地说是字符串   这是常量表达式(§15.28)的值 - 是   “interned”以便使用该方法共享唯一的实例   的String.intern。

并在那里阅读代码示例的注释:

  

这个例子说明了六点:

     
      
  • 同一个包(第7节)中同一个类(第8节)内的文字字符串表示对同一个String对象的引用(§4.3.1)。

  •   
  • 同一个包中不同类中的文字字符串表示对同一个String对象的引用。

  •   
  • 不同包中不同类中的文字字符串同样表示对同一String对象的引用。

  •   
  • 由常量表达式计算的字符串(第15.28节)在编译时计算,然后视为文字。

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

  •   
  • 显式实习计算字符串的结果与具有相同内容的任何预先存在的文字字符串相同。

  •   

答案 2 :(得分:5)

当编译器优化您的字符串文字时,它会发现s1和s2都具有相同的值,因此您需要只有一个字符串对象。这是安全的,因为String在Java中是不可变的。

String s1="Java";
String s2="Java";
System.out.println(s1== s2);

这会得到结果true,因为s1s2指向同一个对象。

字符串池是一种机制,所有已定义的字符串都存储在某个“池”中,并且在创建新的String对象编译器之前检查是否已经定义了这样的字符串。

答案 3 :(得分:2)

实施例

第一个例子

String s1 = "FirstString";
String s2 = "FirstString";

 if(s1 == s2) {
   //This condition matched true because java don't make separate object for these two string. Both strings point to same reference.
 }

第二个例子

String s1= "FirstString";
String s2 = new String("FirstString");

if(s1.equals(s2)) {
  //This condition true because same content.
}

if(s1 == s2) {
  //This condition will be false because in this java allocate separate reference for both of them
}

结论:Java检查字符串是否存在。如果我们使用new创建第二个字符串的对象并且具有不同的内容,那么它创建对象并分配不同的引用。如果我们不使用new创建对象并且具有相同的内容,则它分配与第一个相同的引用字符串包含。

答案 4 :(得分:0)

String s1="Java";
String s2="Java"; 
  

他们是否指向相同的内存位置?

我最初说“不”,但在上面的情况下,请参阅下面提到的StringPool答案,它实际上是肯定的。

  

“当我们创建相同的字符串(没有new关键字)时,是吗?   内容只存储在内存中一次和所有String对象   具有相同的内容只需参考相同的位置“

...有点看到问题"Java Strings and StringPool"

的详细答案
  

“s1和s2的哈希码是相同的。但是哈希码是依赖的   直接在对象的内存位置?“

没有哈希码取决于String的内容

答案 5 :(得分:0)

添加到其他人: 新关键字始终强制来创建新对象。 如果您声明如下:

String s1 = "some";
String s2 = "some";

然后使用String Pooling机制,引用s1和s2将引用具有值“some”的相同String对象。

答案 6 :(得分:0)

当你有

String str1 = new String("BlaBla");  //In the heap!
String str2 = new String("BlaBla");  //In the heap!

然后您通过String运算符(和构造函数)明确创建new对象。 在这种情况下,您将使每个对象指向不同的存储位置。

但如果你有:

String str1 = "BlaBla";        
String str2 = "BlaBla";

那么你就是隐含的构造。 如果它们具有相同的值,则两个字符串文字共享相同的存储,这是因为Java保留了相同字符串的存储! (具有相同值的字符串)

答案 7 :(得分:0)

String s1="Java";
String s2="Java";

都指向同一个对象。更多细节click here

答案 8 :(得分:-2)

YES, Andrew Hare在此链接https://stackoverflow.com/a/2486195/4835894中回答了堆栈溢出问题。

  

基本上,字符串实习池允许运行时通过保留池中的不可变字符串来节省内存,以便应用程序的区域可以重用公共字符串的实例,而不是创建它的多个实例。

相关问题