String需要掌握的内容
-
string的基本特性
-
内存如何分配
-
字段拼接
-
intern()
String的基本特性
简单说明:不可变特性的存在保证了原有存在的对象不能被修改,也是常量池存在的意义,我是这么理解啊。
列子:
打印结果:
good
best
简单说明:根据string的不变性,ex.str原来的对象本身不会做改变,会新建一个新的“test ok‘对象,但大家肯定会有另外一个疑问:
为什么StringExer对象中的Str对象的指引为什么不会随着change方法中的赋值而变更指引?
解释下:change方法作为一个函数运行时就是一个栈帧,而参数是保存局部变量中的,对str的指引修改,是修改了局部变量表中的str的指引值,而非修改了stringExer对象中的str的指引,所以stringExer对象中的str未变更。希望讲清楚了这个问题。
常量池
常量池=HashTable(hash数组 + 链表结构),字符串常量池的存在可以避免相同字符串被多此创建,节省空间。
| jdk6 | jdk7 | |
|---|---|---|
| 常量池存放位置 | 方法区 | 堆中 |
| 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修饰,则还是属于第一种情况。
intern()
方法的目的是将String对象保存到常量池,如果已经存在则直接返回常量池种字符串的地址,若没有则保存,并返回地址。这需要区分jdk版本,可查看上方表格。
保证变量指引字符串常量池种的数据:
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()一个。
练习题:
简单说明:若 s3 == s4有疑惑,请看此处:s3.intern();在字符串常量池种生成”11“,
jdk6中会在方法区创建一个新的对象”11“,也就有了新地址。
jdk7中则不会在字符串常量池中新建”11“对象,而是创建一个指向堆空间先前new的String对象的地址。
再对上题的s3 == s4的扩展:
结果:false; .intern()方法执行顺序改变,导致两个对象的地址不同。
intern()的总结:
字符串常量池的存在可以避免相同字符串被多此创建,节省空间。所以正确使用intern()方法可以有效提高效果(比如:有大量重复字符串对象创建的情况)
\