字符串拼接操作(创建了几个对象?
)
-
String a = "hello" + "world";
-
final String a = "hello"; String b = a + "world";
-
String a = "hello"; String b = a + "world";
一:方式一分析及验证
二:方式二分析及验证
三:方式三分析及验证
含有变量的字符串在拼接时,根据JDK版本不同,底层实现也相应不同;
四:面试题
注意
:JDK9及之后现不做分析(~)
package xyz.xx.chapter1;
/**
* 面试题
* 问:分析下面程序结果并作出合理解释
*
* JDK6 -> false -> invokespecial #7 <java/lang/StringBuilder.append>
* JDK7 -> true -> invokevirtual #7 <java/lang/StringBuilder.append>
* JDK8 -> true -> invokevirtual #7 <java/lang/StringBuilder.append>
* JDK9 -> true -> invokedynamic #16 <makeConcatWithConstants, BootstrapMethods #0>
* JDK11 -> true -> invokedynamic #16 <makeConcatWithConstants, BootstrapMethods #0>
* JDK14 -> true -> invokedynamic #16 <makeConcatWithConstants, BootstrapMethods #0>
*/
public class StringTest5 {
public static void main(String[] args) {
// JDK7及之后,当前语句执行后,字符串常量池中不存在“helloworld”
String a = new String("hello") + new String("world");
a.intern();
String b = "helloworld";
System.out.println(a==b);
}
}
分析:
1> JDK7之前(不包括JDK7),字符串常量池被放在永久代(PernGen)
中,同时永久代(PermGen)
使用的是虚拟机内存;JDK7开始,字符串常量池被移到了堆(Heap)
中,这就意味着在部分情况下,一份字符串不需要实例处两个对象:
2> JDK7及之后,main中第一条语句执行后,字符串常量池中不存在“helloworld”
StringBuilder的toString方法内部直接new了一个String,但是其内部的内容没有直接在字符串常量池中生成(代码中没有出现ldc),所以在JDK8的环境下,intern()会直接拷贝一份原有String的地址到StringTable并返回该地址值
:
五:面试题改编
1> 改编一
package xyz.xx.chapter1;
/**
* 面试题(改编一)
*
* JDK6 -> false -> invokespecial #7 <java/lang/StringBuilder.append>
* JDK7 -> false -> invokevirtual #7 <java/lang/StringBuilder.append>
* JDK8 -> false -> invokevirtual #7 <java/lang/StringBuilder.append>
* JDK9 -> false -> invokedynamic #16 <makeConcatWithConstants, BootstrapMethods #0>
* JDK11 -> false -> invokedynamic #16 <makeConcatWithConstants, BootstrapMethods #0>
* JDK14 -> false -> invokedynamic #16 <makeConcatWithConstants, BootstrapMethods #0>
*/
public class StringTest6 {
public static void main(String[] args) {
String a = new String("hello") + new String("world");
// a.intern();
String b = "helloworld";
System.out.println(a==b);
}
}
2> 改编二
package xyz.xx.chapter1;
/**
* 面试题(改编二)
*
* JDK6 -> false -> invokespecial #7 <java/lang/StringBuilder.append>
* JDK7 -> false -> invokevirtual #7 <java/lang/StringBuilder.append>
* JDK8 -> false -> invokevirtual #7 <java/lang/StringBuilder.append>
* JDK9 -> false -> invokedynamic #16 <makeConcatWithConstants, BootstrapMethods #0>
* JDK11 -> false -> invokedynamic #16 <makeConcatWithConstants, BootstrapMethods #0>
* JDK14 -> false -> invokedynamic #16 <makeConcatWithConstants, BootstrapMethods #0>
*/
public class StringTest6 {
public static void main(String[] args) {
String a = new String("hello") + new String("world");
String b = "helloworld";
a.intern();
System.out.println(a==b);
}
}
3> 改编三
package xyz.xx.chapter1;
/**
* 面试题(改编三)
*
* JDK6 -> true -> invokespecial #7 <java/lang/StringBuilder.append>
* JDK7 -> true -> invokevirtual #7 <java/lang/StringBuilder.append>
* JDK8 -> true -> invokevirtual #7 <java/lang/StringBuilder.append>
* JDK9 -> true -> invokedynamic #16 <makeConcatWithConstants, BootstrapMethods #0>
* JDK11 -> true -> invokedynamic #16 <makeConcatWithConstants, BootstrapMethods #0>
* JDK14 -> true -> invokedynamic #16 <makeConcatWithConstants, BootstrapMethods #0>
*/
public class StringTest8 {
public static void main(String[] args) {
String a = new String("hello") + new String("world");
String b = "helloworld";
a = a.intern();
System.out.println(a==b);
}
}
4> 改编四(解释型)
package xyz.xx.chapter4;
/**
* String.intern() 对象内存分配问题
*
* 问:
* c.intern()注释前和注释后,解释字符串内存分配过程
* 答:
* 前-> +1 +1 +1
* 后-> +1 +1
*
* 总结:
* 适当地使用intern() 在正常实现功能的情况下,可以有效降低String对象产生量
*/
public class StringTest2 {
public static void main(String[] args) {
String a = "hello";
String b = "hello";
String c = a + b;
// c.intern();
String d = "hellohello";
}
}