String 你真的都掌握了吗?

283 阅读3分钟

String需要掌握的内容

  1. string的基本特性

  2. 内存如何分配

  3. 字段拼接

  4. intern()

String的基本特性

1627183198241.png 1627183362794.png

简单说明:不可变特性的存在保证了原有存在的对象不能被修改,也是常量池存在的意义,我是这么理解啊。

列子: 1627183577121.png 打印结果:

good

best

简单说明:根据string的不变性,ex.str原来的对象本身不会做改变,会新建一个新的“test ok‘对象,但大家肯定会有另外一个疑问:

为什么StringExer对象中的Str对象的指引为什么不会随着change方法中的赋值而变更指引

解释下:change方法作为一个函数运行时就是一个栈帧,而参数是保存局部变量中的,对str的指引修改,是修改了局部变量表中的str的指引值,而非修改了stringExer对象中的str的指引,所以stringExer对象中的str未变更。希望讲清楚了这个问题。

常量池

常量池=HashTable(hash数组 + 链表结构),字符串常量池的存在可以避免相同字符串被多此创建,节省空间。

jdk6jdk7
常量池存放位置方法区堆中
string.intern()在常量池是否新建对象会新建对象,因为存放位置不同导致不会,直接引用到先前的对象地址

String的内存分配

1、直接使用双引号声明的:存储在常量池中

2、new String() 声明:存在堆中,string.intern()后存放位置和是否新建对象请看上面常量池的表格。

字段拼接

可以通过class文件反编译,查看到” “+” “本质:

1、”ab“ +”cd“:编译期进行优化成为了"abcd"。

2、String a="ab";String b="cd";String c=a+b; :有变量参与则是通过StringBuilder进行的处理,最后进行toString()会产生一个新的对象。

3、若变量a、b通过final修饰,则还是属于第一种情况。 1627197336107.png

intern()

方法的目的是将String对象保存到常量池,如果已经存在则直接返回常量池种字符串的地址,若没有则保存,并返回地址。这需要区分jdk版本,可查看上方表格。 1627197785222.png

保证变量指引字符串常量池种的数据:

1、String a ="abc";

2、String a=…… .intern();……表示任何形式,比如new String();

面试题

创建几个对象?:

1、String str = new String("ab");

答:两个对象:字符串常量池中一个对象”ab“,(字节码指令:ldc)

堆中的一个new出来的String对象。

2、String c =new String("a") + new String("b");

答:6个: 1、new String("..") * 2 = 4个。

2、StringBuffer一个。

3、StringBuffer.toString()一个。

练习题:

1627199017046.png

简单说明:若 s3 == s4有疑惑,请看此处:s3.intern();在字符串常量池种生成”11“,

jdk6中会在方法区创建一个新的对象”11“,也就有了新地址。

jdk7中则不会在字符串常量池中新建”11“对象,而是创建一个指向堆空间先前new的String对象的地址。

再对上题的s3 == s4的扩展:

1627199532979.png 结果:false; .intern()方法执行顺序改变,导致两个对象的地址不同。

intern()的总结:

1627199642816.png

字符串常量池的存在可以避免相同字符串被多此创建,节省空间。所以正确使用intern()方法可以有效提高效果(比如:有大量重复字符串对象创建的情况)

\