java中String初始化
Java中的引用类型String的初始化,可以通过直接字符串赋值,也可以通过String的构造函数进行初始化,但是这两种初始化方式存在很大差异,接下来,从内存分配的角度来分析它们之间的差异。
package Stringdemo;
public class StringDemo {
public static void main(String[] args) {
//直接赋值法
String str1 = "123";
//构造函数法
String str2 = new String("123");
System.out.println(str1==str2);//输出false
}
}
两种方式都可以得到这个值为"123"的字符串,但是他们在内存中的关系是不一样的。直接赋值法这个"123"是保存在常量池中的,而采用构造函数初始化时,它首先会去常量池中是否有"123",如果存在,则它会在内存中生成一个对象指向常量池中的"123",而它自己再指向新创建的对象的地址。因此,它们两个的地址是不一样的。
图解:
它们根本上的区别是使用构造函数法会生成多余的对象,写法上直接赋值法也更加简洁,因此直接赋值写法是推荐的。
String a="a";
String a1=a+1;//使用变量拼接
String a2="a1";
System.out.println(a1==a2);//false
上面的例子中a1和a2都是直接赋值或者拼接的相同的字符串,但是它们的指向却不相同。这里需要从编译时和运行时两个不同时期进行分析,编译时,所有的变量都没有值,只有常量有值,所以a1是不确定的,而a2此时已经有了值和指向了,a1必须要到运行时才能有值,且它是由a+1拼接出来的对象,所以它们指向不同。
String a="a";
String a1="a"+1;//直接使用字符拼接,编译时就会存在"a1"
String a2="a1";
System.out.println(a1==a2);//true
这个例子就能说明,两者都在编译时被赋值,两者的指向也是相同,指向了同一个"a1"。
final String a="a"; //a是常量
String a1=a+1;
String a2="a1";
System.out.println(a1==a2);
这个例子和上一个例子本质是一样的,它们都是编译时就存在的。
package Stringdemo;
public class StringDemo {
public static void main(String[] args) {
// //直接赋值法
// String str1 = "123";
// //构造函数法
// String str2 = new String("123");
//
// System.out.println(str1==str2);
String a=getA();//进行函数赋值
String a1=a+1;
String a2="a1";
System.out.println(a1==a2);//false
}
public static String getA() {
return "a";
}
}
因为方法总是在运行时才能有返回值,所以a1在运行时才能拿到值进行拼接,指向拼接的新对象,所以它们指向不同。将上述代码修改一下,得到:
final String a = getA(); //定义为常量
String a1 = a+1;
String a2 = "a1";
System.out.println(a1+" "+a2);//"a1" "a1"
System.out.println(a1==a2);//false
它们的指向不同还是因为a采用了函数赋值,而函数只有运行时才能有值,所以导致了这样的结果。
java中String类型的初始化,要注意两种方式的根本不同是构造函数会生成至少一个新对象,而直接赋值性能更优。对于直接赋值,也要注意区分(变量+“常量”)时,对它的指向的影响,注意区分编译时和运行时的职能!编译时会对常量优化,运行时则是对变量或者方法进行赋值或者返回值。