转自http://expert.csdn.net/Expert/topic/1826/1826723.xml?temp=.8720056
eg:String s="Hello";
编译器在上述程序编译时,将字符H,e,l,l,o放入这个类文件的特殊区,这个区称为类文件的常量缓冲区(Constant pool)(一个由字符串常数和其他常数组成的集合)
编译器还会产生字节码指令,间接地将这个值的索引赋给字符串变量,编译器不会在缓冲区放置字符串常数的多个副本,如,即使源代码出现多个"abc"字符串常数,编译器也只在常量缓冲区放置这个字符串的一个副本(去掉双引号)(后面有个例子)。
在jvm加载类文件时,它为每个常量缓冲区中的字符串常数创建一个字符串对象(创建过程发生于幕后),将每个字符串对象的值初始化为String对象的值初始化为字符串常数包含的字符,并修改常量缓冲区的内存副本,使得加载字符串常数(在缓冲区中)索引的字节指令获得字符串对象的引用。
上面这段话很难理解(我花了半天才弄明白一点点),上过程即为:将源代码中描述的每个字符串常量变为运行时的一个字符串对象。
又如:String s=new String("Hello");
该段代码创建一个对象,错!!实际上其创建了两个对象,首先在加载类文件时,创建一个包含H,e,l,l,o的字符串对象,然后将该对象的引用作为参数传递给String(String str)构造函数,从而创建一个内部char数组(长度为5),然后构造函数从这个字符串对象中抽取Hello的值放入该数组中,最后将新的String对象的引用赋给s中。说了这么多,做两个练习。^_^
eg:
1. String s1="abc",s2="abc";
s1==s2;//true
String s1="abc",s2=new String("abc";)
s1==s2;//false
解:当编译器在源代码中遇到"abc"时,将其放入常量缓冲区中,但如果编译器遇到该字符串的第二个副本,就不将其放入常量缓冲区中,而是产生字节码指定来引用第一个字符串常量,在运行时当s1和s2都被赋值为对字符串对象(加载类文件时创建)的引用,它们实际指向包含"abc"的同一String对象。
通常缓冲区中的由字符串常量创建的字符串对象是固定的,即这些字符串对象保存在包含唯一字符串(即字符串带唯一的字符序列)内存缓冲区中,String类对这个内存缓冲区进行维护,只有两种方法可以固定String
一,在源代码中使用String常数。二,使用String的intern方法。
eg:String s1="abc",s2=new String ("abc").intern;
s1==s2;//true下面给出整个源代码
public class StringTest{
public static void main(String[] args){
String s1,s2,s3,s4;
s1="abc";
s2="abc";
s3=new String("abc");
s4=new String("abc").intern();
System.out.println(s1==s2);
System.out.println(s1==s3);
System.out.println(s1==s4);
}
}