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(),这样又在堆中非字符串池的地方开辟了块内存,创建了一个字符串对象。




那么,就在问去几个问题,下面的几段代码分别创建了几个对象
1、String a="ab";
2、String b="ab";
3、String d="abcd";4、String c=a+"cd";
5、String e=new String("abcd")

6、String f="aaa"+"bbb";

答案:

第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个)