JAVA中字符串的两种创建方式
我们知道,在Java中有两种创建字符串对象的方式:1)采用直接赋值的方式赋值 2)采用new关键字新建一个字符串对象。这两种方式在性能和内存占用方面存在着差别。
方式一:采用直接赋值的方式赋值
public class Test {
public static void main(String[] args) {
String str = "abc";
String str1 = "abc";
System.out.println(str1==str);
}
}
采用直接赋值的方式创建一个字符串时,JVM首先会去字符串池中查找是否存在"abc"这个对象,如果不存在,则在字符串池中创建"abc"这个对象,然后将池中"abc"这个对象的引用地址返回给字符串常量str,这样str会指向池中"abc"这个字符串对象;如果存在,则不创建任何对象,直接将池中"abc"这个对象的地址返回,赋给字符串常量。
在本例中,执行:str == str1,会得到以下结果:
这是因为,创建字符串对象str1时,字符串池中已经存在"abc"这个对象,直接把对象"abc"的引用地址返回给str1,这样str1指向了池中"abc"这个对象,也就是说str和str1指向了同一个对象,因此语句System.out.println(str == str1)输出:true。
方式二:采用new关键字新建一个字符串对象
public class Test {
public static void main(String[] args) {
String str = new String("abc");
String str1 = new String("abc");
System.out.println(str1==str);
}
}
采用new关键字新建一个字符串对象时,JVM首先在字符串池中查找有没有"abc"这个字符串对象,如果有,则不在池中再去创建"abc"这个对象了,直接在堆中创建一个"abc"字符串对象,然后将堆中的这个"abc"对象的地址返回赋给引用str,这样,str就指向了堆中创建的这个"abc"字符串对象;如果没有,则首先在字符串池中创建一个"abc"字符串对象,然后再在堆中创建一个"abc"字符串对象,然后将堆中这个"abc"字符串对象的地址返回赋给str引用,这样,str指向了堆中创建的这个"abc"字符串对象。
在这个例子中,执行:str == str1,得到以下结果:
因为,采用new关键字创建对象时,每次new出来的都是一个新的对象,也即是说引用str和str1指向的是两个不同的对象,因此语句System.out.println(str == str1)输出:false。
注:String对象是不可变的。因为这样可以保证多个引用可以同事指向字符串池中的同一个对象。如果字符串是可变的,那么一个引用操作改变了对象的值,对其他引用会有影响,这样显然是不合理的。
字符串常量池的优缺点:字符串常量池的优点就是避免了相同内容的字符串的创建,节省了内存,省去了创建相同字符串的时间,同时提升了性能;另一方面,字符串常量池的缺点就是牺牲了JVM在常量池中遍历对象所需要的时间,且需要一段内存来作为常量池.
总的来说;1)每一个字符串常量都指向字符串池中或者堆内存中的一个字符串实例;2)字符串对象值是固定的,一旦创建就不能再修改;
下面是另一个相关的问题:
public class Test {
public static void main(String[] args) {
String str = "abcdef";
String str1 = "abc";
String str2 = "def";
String str3 ="abc"+"def";
String str4 = str1+str2;
String str5 = new String("abc")+"def";
System.out.println(str==str3);
System.out.println(str==str4);
System.out.println(str==str5);
}
}
代码输出如下:
对于为什么会出现这样的结果,我通过网上的一些说法认为就是只有使用引号包含文本的方式创建的String对象之间使用“+”连接产生的新对象才会被加入字符串池中。对于所有包含new方式新建对象和直接运用字符串变量的“+”连接表达式,它所产生的新对象都不会被加入字符串池中,都放在了堆内存中.
总结:
在两种方法中,直接赋值的方法更加便利且内存应用较少,所以在以后的应用中都应该采用直接赋值的方法.
字符串是常量,字符串池中的每个字符串对象只有唯一的一份,可以被多个引用所指向,避免了重复创建内容相同的字符串;通过直接赋值创建的字符串对象存放在字符串池中,通过关键字new出来的字符串对象存放在堆中。且在字符串常量池中的字符串如果没有引用,不会被java中的垃圾回收机制所回收.
直接赋值创建的字符串对象存放在字符串池中,通过关键字new出来的字符串对象存放在堆中。且在字符串常量池中的字符串如果没有引用,并不会被java中的垃圾回收机制所回收,而是一直存在着等着被引用.