String是在代码中非常常见的一种数据类型.它能直接像基本类型一样直接赋值(String str = "test"),也能像引用类型一样创建一个实例(String str = new String("test")),当然毫无疑问String是引用类型.
(1)Sring str = "test"; //此种方式会在字符串常量池中创建一个"test'"常量,当有一个新的变量同样也赋值为"test"时,这个新的变量也指向了这个"test"常量.
(2)String str = new String("test"); //此种方式会在堆内存中new一个"test"对象实例,详细分析见下文.
(1)只有使用引号包含文本的方式创建的String对象之间使用"+"连接产生的新对象才会被加入到字符串池中。
String str = "hello" + "world"; //这才会在字符串池中创建一个"helloworld"字符串,而不是去堆中创建一个String对象。
(2)对于所有包含new方式创建对象(包括null)的“+”连接表达式,它所产生的新对象都不会被加入字符串池中。
String str1 = "hello";
String str2 = "world";
String str = str1 + str2; //此时str产生的"helloworld"并不会在字符串池中,而是在堆中创建一个String对象。
综上.
tring str1 = "hello";
String str2 = "world";
String str3 = "hello" + "world";
String str4 = str1 + str2;
//str3 == str4 ->false,原因见上。str4是在堆中创建的String对象,str3是在字符串池中创建的的"helloworld"
但是!以上的情况是一般情况!
special1.这个例子实际仔细一分析也很好理解,STR1和STR2都是final常量,它们在类编译时就已经确定。
public class Demo {
public static final String STR1 = "hello";
public static final String STR2 = "world"; public static void main(String[] args) {
String str3 = "hello" + "world";
String str4 = STR1 + STR2;
System.out.println(str3 == str4); //true
}
}
special2.这个例子和上个例子不同在于final常量被声明的时候,并没有马上给它赋值。在str4被赋值前STR1+STR2是何值都还不确定,STR1和STR2在赋值前实际上就是一个变量而不是一个常量,那么str4就不能在编译期被确定,而只能在运行时被创建。
public class Demo {
public static final String STR1 ;
public static final String STR2 ;
static {
STR1 = "hello";
STR2 = "world";
} public static void main(String[] args) {
String str3 = "hello" + "world";
String str4 = STR1 + STR2;
System.out.println(str3 == str4); //false
}
}
回到开始提到的问题:
String str = new String("test"); //创建了几个对象?
2个。在类加载时会创建一个"xyz"对象放到字符串常量池中,在运行时会从常量池中赋值一份到堆中,并且将堆中这个对象的引用交给s1持有。