案例1:
String a = "ab";
String bb = "b";
String b = "a"+bb;
System.out.println(a==b);
这里输出的结果是false,为什么?
“String+变量”因为编译时无法进行优化,所以这一条语句的操作是在运行时进行的,且会产生新的对象,而不是直接从 jvm 的 string常量池中获取。
java 中 String 的“+”运算符编译后其实是转换成了这样的代码:
String b = new StringBuilder().append("a").append(bb).toString();
其中StringBuilder类重写的toString方法使用 new String(…)来构造一个 String 对象。JDK中的源代码如下:
@Override
public String toString() {
// Create a copy, don't share the array
return new String(value, 0, count);
}
通过new操作符创建的字符串对象不指向字符串池中的任何对象,但是可以通过使用字符串的intern()方法来指向其中的某一个。
我们来看一道经典面试题:
String str = new String(“abc”) 创建多少个对象?
这段代码执行过程如下:
1、在常量池中查找是否有“abc”对象。
1.有则返回对应的引用实例;
2.没有则创建对应的对象实例。
2、在堆中 new 一个 String(“abc”) 对象。
3、将对象地址赋值给str,创建一个引用。
所以,常量池中没有“abc”字面量则创建两个对象,否则创建一个对象,以及创建一个引用。
根据字面量,往往会提出这样的变式题:
String str1 = new String(“A”+“B”) ; 会创建多少个对象?
String str2 = new String(“ABC”) + “ABC” ; 会创建多少个对象?
str1:
字符串常量池:“A”,“B”,“AB” : 3个
堆:new String(“AB”) :1个
引用: str1 :1个
总共 : 5个
str2 :
字符串常量池:“ABC” : 1个
堆:new String(“ABC”) :1个
引用: str2 :1个
总共 : 3个
案例2:
一个特殊的例子:
//“+”连接的都是字符串常量
String str = “This is only a” + “ simple” + “ test”;
StringBuffer builder = new StringBuilder(“This is only a”).append(“ simple”).append(“ test”);
我们一般认为速度 StringBuilder>StringBuffer>String,但在此案例中
你会很惊讶的发现,生成 str 对象的速度简直太快了,而这个时候 StringBuffer 居然速度上根本一点都不占优势。其实这是 JVM 的一个把戏,实际上:
String str = “This is only a” + “ simple” + “test”;
其实就是:
String str = “This is only a simple test”;
所以不需要太多的时间。但大家这里要注意的是,如果你的字符串是来自另外的String 对象的话,速度就没那么快了,譬如:
String str2 = “This is only a”;
String str3 = “ simple”;
String str4 = “ test”;
String str1 = str2 +str3 + str4; //“+”连接的是字符串变量
这时候 JVM 会规规矩矩的按照原来的方式去做。