JVM如何为java中的String分配内存?

时间:2014-08-05 15:53:36

标签: java string jvm

我有这样的情景 -

 String s = "abc", t="abc"; //LINE 1
 System.out.println(s==t); // definitely it would return true; //LINE 2
 s=s+"d"; t=t+"d";   //LINE 3
 System.out.println(s==t); // output would be false; but why??
 s=s.intern(); t=t.intern();
 System.out.println(s==t); // it would return true;

我想知道为什么第二个print语句返回false。请提供任何解释相同的参考链接。

在第1行创建t;实习生被召唤并指出“abc”为什么不在第3行召唤实习生?

5 个答案:

答案 0 :(得分:6)

java字符串是immutable

这意味着当您执行s=s+"d"之类的操作时,实际上是在创建一个全新的字符串,并将其分配给s。

最重要的是,编译器会执行常量检测和分配,因此当您编写s="abc", t="abc"时,编译器会重新使用相同的引用,并且您的代码实际上是s=t="abc"

所以你从完全相同的字符串实例开始(感谢编译器优化)并将其转换为2个相同但又不同的字符串,此时s==t为假(s.equals(t)为真,如它比较内容而不是内存中的地址。)

接下来是intern()。 intern()的作用是在字符串缓存中查找相同的字符串并返回它。如果它没有找到相同的条目,则将提供的参数放入缓存并返回参数。所以s=s.intern()将s放入字符串缓存并返回它(因此s保持不变),但以下调用t=t.intern()实际返回s,以便再次s==t

答案 1 :(得分:4)

String s = "abc", t="abc";

s == ttrue,因为Java会自动实习String个文字。在这种情况下,String文字"abc"已被实习,st都指向同一个实例。因此s == ttrue

s = s + "d"; t = t + "d";

Java中的字符串是不可变的。因此,您分配给st的内容是已构建的两个 Strings。因此,他们没有指向同一个实例。这就是s == t返回false

的原因
s = s.intern(); t = t.intern();

在这里,你强行将s.intern()中的字符串插入。由于st都包含相同的字符串值,因此JVM看到t是相同的,并使其指向与s相同的实例化实例。因此s == ttrue

总的来说,建立字符串相等应该通过.equals()而不是==完成; ==仅比较引用类型的引用,而不是值。

答案 2 :(得分:4)

字符串是“特殊”的Java对象。

JVM尝试重用相同的引用(这就是String s = "abc", t="abc";导致st指向同一实例的原因),但是,当处理实例时(例如t = t +) “d”)创建一个新实例,因此,引用不是相同的

为了比较字符串,您必须使用.equals()方法。

intern()导致从String类中的字符串池中创建规范表示( http://docs.oracle.com/javase/7/docs/api/java/lang/String.html#intern%28%29

答案 3 :(得分:1)

Java语言规范明确涵盖了这种特殊情况。以下是chapter 3.10.5. "String Literals"的引用:

  
    

此外,字符串文字始终引用类String的相同实例。这是因为字符串文字 - 或者更常见的是常量表达式的值(第15.28节) - 是“实习”,以便使用String.intern方法共享唯一实例。 / p>   

如您所见,只有常量表达式被实现。因此,代码的前四行等同于:

String s = "abc".intern(), t="abc".intern(); 
System.out.println(s==t); 
s=s+"d".intern(); t=t+"d".intern();   
System.out.println(s==t); 

表达式s+"d"t+"d"不是常量,因此不会被实习。

JLS甚至为an example提供了有用的注释。以下是相关部分:

package testPackage;
class Test {
    public static void main(String[] args) {
        String hello = "Hello", lo = "lo";
        System.out.print((hello == ("Hel"+lo)));
    }
}
  
    

输出:false     注意:在运行时通过串联计算的字符串是新创建的,因此是不同的。

  

答案 4 :(得分:0)

因为当你连接String时,你会生成一个新的对象引用,除非它们是文字String

请注意,intern的{​​{1}}指向同一个文字String对象引用。