关于Java中字符串的存储方式
创建方式1:
1 | String s = "123"; |
首先在栈中创建字符串”123”,随后调用intern(),检查字符串常量池中是否存在对这个字符串的引用,如果有则返回对他的引用,没有的话则将这个字符串存入字符串常量池。如果改字符串已经存储在堆中,intern方法会直接将其引用到字符串常量池中
s返回的是字符串常量池中”123”的引用
创建方式2:
1 | String s=new String("123"); |
这个语句会将”123”放入字符串常量池,在队中创建一个字符串对象,里面的值和常量池中的一样,返回引用
因此会创建两个对象,而引用指向堆中的对象
创建方式3:
1 | String s=new String("1")+new String("23"); |
这种方式底层等价于用StringBuilder进行拼接,其最大的区别就是不会在字符串常量池中创建对象,而是只在堆中创建并返回其引用
一些场景
场景一
1 | String s1 = "123"; |
返回为true,因为s1为常量池中”123”的引用,s2返回的也是常量池中”123”的引用,所以返回为true
1 | String s1 = new String("123"); |
这种情况,s2和上面相同,但s1为堆中对象的引用,所以为false
场景二
1 | String h = new String("hw"); |
h为堆中对象的引用,h2为字符串常量池中对象的引用,h1也是
字符串常量池中对象的引用,所以答案为false,true,false
1 | String s = new String("1") + new String("1"); |
s为堆中对象的引用,s2由于字符串常量池中不存在对象,所以将调用字符串的引用存入进去,所以s2还是堆中对象的引用,s1在创建时因为字符串常量池中已经有了该对象,所以直接返回该对象的引用,而该对象的引用对应的是堆中对象,所以s,s1,s2得到的是同一个引用,所以为true,true,true
场景三
1 | String s = new String("1") + new String("1"); |
s为堆中对象的引用,s1在字符串常量池中创建对象并返回引用,s2返回的是s1的引用,所以为false,true,false