转自 http://blog.youkuaiyun.com/lonelyroamer/article/details/7354743
String的创建有两种形式,一种是直接放在双引号("");
一种是直接用new的方式创建;
在Java中,String和StringBuffer,StringBuilder都能表示一个字符串。String的定义是:表示一个字符串常量。那么,看下面的一段代码: String str="abc"; str="def"; 常量,基本数据类型的常量是不可变的,可是我们可以看到,这里所谓的字符串常量str是可变的。这是为什么呢? 引用数据类型的常量,指的是引用的对象不可变,而引用,也即句柄是可变的。也就是多,当一个String类型的字符串 改变时,实际上是它指向的内存单元发生了改变,原来的内存单元的内容并没有发生改变。 StringBuffer的定义是:表示一个字符串变量。StringBuffer strbuf="abc";这样的初始化是错误的,要想初始化一个 StringBuffer类型的字符串必须使用new来初始化,如1、StringBuffer strbuf=new StringBuffer("abc"); 2、strbuf=new StringBuffer("def"); 3、strbuf.append("def");由此可见,StringBuffer字符串变量,指的是不仅引用可变,引用的对象也是可变的。 下面的两个例子可以很好的说明这个问题。 1、 String str1="abc"; String str2=str1; StringBuffer str3=new StringBuffer("abc"); StringBuffer str4=str3; str1=str1+str2; str3=str3.append(str4); System.out.println(str1); System.out.println(str2); System.out.println(str3); System.out.println(str4); 输出的结果: abcabc abc abcabc abcabc
2、 public class Test5 { public static void main(String[] args) { String str1="java"; StringBuffer str2=new StringBuffer("java"); test(str1); test(str2); System.out.println(str1); System.out.println(str2); } public static void test(String str) { str=str.replace("j", "i"); } public static void test(StringBuffer str) { str.append("c"); } } 程序的输出结果为 java javac (String对象的处理确实与其他的对象有所区别,在深度克隆中也有体现,对它的处理更像是对一个基本数据类型的处理。 这主要就是因为它是一个常量的原因。)
字符串是一个引用数据类型String对象肯定是存放在堆中的。关键在于,String对象是一个final的常量,JVM为了管理String和高效性
在堆中,会用一个特殊的字符串池来保存字符串直接量所谓的字符串直接量,就是指字符串由字符串、数值常量直接构成,没有变量,也没有方
例如 String a="abc"; String b="abc"+10; String c="abc"+"def"; 这样的字符串,JVM在编译的时候就能完全确定这个字符串,就可以在字符串池中创建该字符串,如果字符串池中已经有这样的 String,就让该变量直接指向在字符串池中的该字符串。 而另外一些不是字符串直接量的字符串 例如 String a="abc"+"abc".lenght(); String b=a+"asc"; JVM无法在编译的时候就确定该字符串,就只能在程序运行期间,在堆中非字符串池中的地方开辟内存,存放这样的字符串。
1、String a="abc"; 2、String b=new String("abcdef"); 上面的两个创建字符串的方法到底分别创建了几个对象? 第1行,创建了一个对象,它是一个字符串直接量,直接被创建存放在字符串池中。 第2行,创建了2个对象,"abcdef"本身就是一个字符串直接量,被创建后存放在字符串池中,然后,它又作为一个参数, 传递给了构造器new String(),这样又在堆中非字符串池的地方开辟了块内存,创建了一个字符串对象。
6、String f="aaa"+"bbb";那么,就在问去几个问题,下面的几段代码分别创建了几个对象 1、String a="ab"; 2、String b="ab";4、String c=a+"cd";3、String d="abcd";
5、String e=new String("abcd")
答案:
第1行,1个、因为字符串池还是空的,不存在字符串"ab",所以在字符串池创建了一个对象"ab"。
第2行,0个、因为字符串池中"ab"已经存在,所以没有创建,直接将b指向"ab";
第3行,1个、因为也是在字符串池中创建了一个"abcd"对象
第4行,2个、先在字符串池中创建"cd",因为采用了变量,所以要在堆中非字符串池中在创建一个对象a+"cd";
第5行,1个、因为字符串池中已经存在"abcd",直接将他作为一个参数传给构造器new一个新的对象。
第6行,1个,因为在编译的时候就能确定f的值,所以只创建一个"aaabbb"到字符串池中;(很多人误解为3个)