首先直接看这样的两个字符串的声明:
String s1 = new String("TestString");
String s2 = "TestString";
对于这样两个字符串的声明在内存中的分布如下图:
字符串s1由于是new的结果,那么首先s1作为一个变量会在栈内存中开辟空间用来保存该变量,然后在堆内存中开辟一块空间用来保存这个字符串对象,同时,也正是因为s1作为一个字符串,在开辟字符串对象空间的同时,在堆内存中也会把该字符串常量保存在字符串常量池当中,所以说,一次new的字符串对象会在堆内存当中产生两个字符串对象。
对于字符串s2这种初始化赋值的方式,首先会在字符串常量池当中进行寻找,如果字符串常量池当中包含该字符串,则直接将该变量指向该字符串常量,如果不包含该字符串,则会新创建一个字符串常量到字符串常量池当中。
上述两种字符串创建的方式,s1会创建两个字符串对象,其中一个是new在堆内存上的字符串对象,一个是在字符串常量池中保存的一份字符串,而s2有可能不用创建对象,若该常量字符串存在则不需要再次进行创建,若不存在则需要在字符串常量池当中进行创建。
接下来看一下字符串在编译期和运行器的分析比较
同样先来一段代码:
public class StringObject {
public static void main(String[] args) {
//eg1
String a = "a1";
String a1 = "a" + 1;
System.out.println(a == a1); //true
//eg2
String b = "b1";
int bb = 1;
String b1 = "b" + bb;
System.out.println(b == b1); //false
//eg3
String c = "c1";
final int cc = 1;
String c1 = "c" + cc;
System.out.println(c == c1); //true
//eg4
String d = "d1";
final int dd = getDd();
String d1 = "d" + dd;
System.out.println(d == d1); //false
}
public static int getDd(){
return 1;
}
}
上述四种情况用来比较两个字符串对象是否为同一个对象
对于eg1中的a1和a,由于两个变量都是常量字符串,当变量a初始化后就会在字符串常量池当中含有”a1”字符串,创建a1时就会先从字符串常量池当中寻找,此时就会找到,直接将已有的字符串常量对象赋值给a1变量,因此a1和a的对象比较结果就相同。
对于eg2中的b1和b,由于bb是一个变量,因此只有在运行期才能确定,所以返回结果为false
对于eg3和eg2中的区别在与变量cc使用了final修饰符,也就是说此处的cc相当于一个常量,在编译期已经将其替换,所以就和eg1类似,两个字符串对象为为同一个对象
然而对于eg4,虽然变量dd前也使用了final进行修饰,但是变量dd的值本身是通过一个静态方法的返回值进行初始化的,方法的执行是在运行期,所以结果为两个对象不是同一个对象。
!!!!初次学习,不正之处,望指正!!!!