环境: JDK6.0 Jad1.5.8(Java反编译工具)
先看测试代码与问题:public class StringObjectValueStack {
/*
* new String("value") 到底有几个对象?
*/
public void methodString () {
String object = new String("value");
}
/*
* 为什么 String += "line"; 效率低下?
*/
public void methodManyString () {
String manyObject = "" ;
for (int index = 0 ; index < 10 ; index ++) {
manyObject += "line" ;
}
}
/*
* 为什么要用StringBuffer呢?
*/
public void methodStringBuffer () {
StringBuffer stringBuffer = new StringBuffer() ;
for (int index = 0 ; index < 10 ; index ++) {
stringBuffer.append("line") ;
}
}
/*
* 为什么要用StringBuilder呢?
*/
public void methodStringBuilder () {
StringBuilder stringBuilder = new StringBuilder() ;
for (int index = 0 ; index < 10 ; index ++) {
stringBuilder.append("line") ;
}
}
}
看反编译结果:public class StringObjectValueStack {
public StringObjectValueStack() {
// 0 0:aload_0
// 1 1:invokespecial #8 <Method void Object()>
// 2 4:return
}
public void methodString() {
String object = new String("value");
// 0 0:new #15 <Class String> 创建了一个实例对象 new String()
// 1 3:dup
// 2 4:ldc1 #17 <String "value"> 创建了第二个实例对象
// 上面的 “value” 双引号的字符常量 第一次创建在 <字符常量缓冲区(Data Segment)> 中
// 下次再发现调用 "value" , 直接去 Data Segment 中拿值 , 不再新建
// 3 6:invokespecial #19 <Method void String(String)>
// 4 9:astore_1
// 5 10:return
// 至此共创建了两个对象
}
public void methodManyString() {
String manyObject = "";
// 0 0:ldc1 #25 <String "">
// 1 2:astore_1
for(int index = 0; index < 10; index++)
//* 2 3:iconst_0
//* 3 4:istore_2
//* 4 5:goto 31
manyObject = (new StringBuilder(String.valueOf(manyObject))).append("line").toString();
// 5 8:new #27 <Class StringBuilder> 在 循环体内 创建StringBuilder对象
// 虽然代码为 String += "line" ; 但编译器实际创建的还是StringBuilder对象来处理字符串
// 注意 JDK1.4 版本以前,编译器 实际调用的是StringBuffer, 直到 JDK1.5以后,底层用StringBuilder代替
// 6 11:dup
// 7 12:aload_1
// 8 13:invokestatic #29 <Method String String.valueOf(Object)>
// 9 16:invokespecial #33 <Method void StringBuilder(String)>
// 10 19:ldc1 #34 <String "line">
// 如果 <字符常量缓冲区(Data Segment)> 没有 "line" 的串对象,则创建了一个对象,以后每循环一次重复使用,不再新建
// 11 21:invokevirtual #36 <Method StringBuilder StringBuilder.append(String)>
// 12 24:invokevirtual #40 <Method String StringBuilder.toString()>
// 13 27:astore_1
// 14 28:iinc 2 1
// 15 31:iload_2
// 16 32:bipush 10
// 17 34:icmplt 8
// 18 37:return
// 至此,使用 String string += "line" ; 在循环体中,循环多少次,就创建多少个全新的StringBuilder对象
}
public void methodStringBuffer() {
StringBuffer stringBuffer = new StringBuffer();
// 0 0:new #48 <Class StringBuffer> 新建 StringBuffer 对象
// 1 3:dup
// 2 4:invokespecial #50 <Method void StringBuffer()>
// 3 7:astore_1
for(int index = 0; index < 10; index++)
//* 4 8:iconst_0
//* 5 9:istore_2
//* 6 10:goto 23
stringBuffer.append("line"); // 只是调用 StringBuffer 的 append 方法 垒加 字符串 并未创建新对象
// 7 13:aload_1
// 8 14:ldc1 #34 <String "line">
// 如果 <字符常量缓冲区(Data Segment)> 没有 "line" 的串对象,则创建了一个对象,以后每循环一次重复使用,不再新建
// 9 16:invokevirtual #51 <Method StringBuffer StringBuffer.append(String)>
// 10 19:pop
// 11 20:iinc 2 1
// 12 23:iload_2
// 13 24:bipush 10
// 14 26:icmplt 13
// 15 29:return
// 至次,只创建了一个StringBuffer对象
}
public void methodStringBuilder() {
StringBuilder stringBuilder = new StringBuilder();
// 0 0:new #27 <Class StringBuilder> 新建 StringBuilder 对象
// 1 3:dup
// 2 4:invokespecial #57 <Method void StringBuilder()>
// 3 7:astore_1
for(int index = 0; index < 10; index++)
//* 4 8:iconst_0
//* 5 9:istore_2
//* 6 10:goto 23
stringBuilder.append("line"); // 只是调用 StringBuilder 的 append 方法 垒加 字符串 并未创建新对象
// 7 13:aload_1
// 8 14:ldc1 #34 <String "line">
// 如果 <字符常量缓冲区(Data Segment)> 没有 "line" 的串对象,则创建了一个对象,以后每循环一次重复使用,不再新建
// 9 16:invokevirtual #36 <Method StringBuilder StringBuilder.append(String)>
// 10 19:pop
// 11 20:iinc 2 1
// 12 23:iload_2
// 13 24:bipush 10
// 14 26:icmplt 13
// 15 29:return
// 至次,只创建了一个StringBuilder对象
}
}