一、JAVA中字符串的两种创建方式
我们知道,在Java中有两种创建字符串对象的方式:
1)采用直接赋值的方式赋值
String str1 = "abc";
采用这种方法去创建字符串时,JVM会在方法区的字符串常量池中寻找这个字符串是否存在,如果存在则不去创建,让创建的对象直接引用其在字符串常量池中的地址;如果不存在则在字符串常量池中创建这个字符串并且返回这个字符串在常量池中的地址。
编辑
2)采用new关键字新建一个字符串对象
String str2 = new String("abc"); 复制代码
采用new关键字新建一个字符串对象时,JVM首先在字符串池中查找有没有"abc"这个字符串如果有,则不在池中再去创建"abc"这个对象了,直接在堆中创建一个"abc"字符串对象,然后将堆中的这个"abc"对象的地址返回赋给引用str,这样,str就指向了堆中创建的这个"abc"字符串对象;如果没有,则首先在字符串池中创建一个"abc"字符串对象,然后再在堆中创建一个"abc"字符串对象,然后将堆中这个"abc"字符串对象的地址返回赋给str引用,这样,str指向了堆中创建的这个"abc"字符串对象。
注意:这种方法本质是在堆区引用字符串常量池中的地址,每次new的对象,在堆上都会创建一个新的对象指向常量池。
编辑
这两种创建方法其实在创建性能上和访问上是有区别的。(堆区创建带来的性能开销)
二、两种创建方法字符串指向比较
public class Demo1 { public static void main(String[] args) { String str1 = "abc"; String str2 = new String("abc"); String str3 = "abc"; System.out.println(str1.equals(str2)); System.out.println(str1 == str2); System.out.println(str1 == str3); } }
编辑
这两种方法创建出的字符串虽然内容是一样的,但指向是不一样的。str1和str3直接指向的是常量池的地址,str2指向堆的地址。(参考上面两个图)。
再看下面的代码:
public class Demo1 { public static void main(String[] args) { String str1 = "abcdef"; String str2 = "abc"; String str3 = "def"; String str4 = "abc" + "def"; String str5 = str2+str3; String str6 = new String("abc"+"def"); System.out.println(str1 == str4); System.out.println(str1 == str5); System.out.println(str1 == str6); } }
编辑
这里的str1 == str4很好理解,“abc” + “def”这一步在编译期间会合并成“abcdef”所以输出true;str1 == str5这里的str5出现这样的结果,别的一些说法认为只有使用引号包含文本的方式创建的String对象之间使用“+”连接产生的新对象才会被加入字符串池中。对于所有包含new方式新建对象和直接运用字符串变量的“+”连接表达式,它所产生的新对象都不会被加入字符串池中,都放在了堆内存中。
我对str5的理解是因为str2和str3以及是存在的对象了,所以寻找的第一位置是堆内存所以它并不会再进一步去其对应的常量池中寻找拿出再去拼接这两段字符串。所以只能将他俩在堆区完成操作并且放在堆中导致返回结果是false。
指向地址查看:
public class Demo1 { public static void main(String[] args) { String str1 = "abcdef"; String str2 = "abc"; String str3 = "def"; String str4 = "abc" + "def"; String str5 = str2+str3; System.out.println(System.identityHashCode(str1)); System.out.println(System.identityHashCode(str2)); System.out.println(System.identityHashCode(str3)); System.out.println(System.identityHashCode(str4)); System.out.println(System.identityHashCode(str5)); } }
编辑
这样就很明显的看出这些创建方式对象的引用是什么了。
总结:
new创建出的对象指向均不相等,字符串的创建无论是哪种方式,都需要先在字符串常量池中寻找该字符串是否存在。
如果有不正确的地方请指出,欢迎一起讨论!