Java中何时用String,何时用StringBuilder

52 篇文章 0 订阅
大家都知道,String对象是不可变的,不可变性会带来效率问题。为String对象重载“+”操作符时,都会自动生成一个新的String对象。
也有人说,String在上述的问题中已经会自动引入StringBuilder来解决效率问题。


为此,我在《Java编程思想》中找到了答案。


第一个小例子:

package com.linc.TestString;

public class TestString {
	public static void main(String[] args)
	{
		String mango = "mango";
		String someting = "abc" + mango + "def" + 47;
		System.out.println(someting);
	}
}
执行编译,命令:
javac TestString.java
用javap来反编译上述代码,看看都发生了什么故事:
javap -c TestString


结果如下:

Compiled from "TestString.java"
public class com.linc.TestString.TestString extends java.lang.Object{
public com.linc.TestString.TestString();
  Code:
   0:	aload_0
   1:	invokespecial	#1; //Method java/lang/Object."<init>":()V
   4:	return

public static void main(java.lang.String[]);
  Code:
   0:	ldc	#2; //String mango
   2:	astore_1
   3:	new	#3; //class java/lang/StringBuilder
   6:	dup
   7:	invokespecial	#4; //Method java/lang/StringBuilder."<init>":()V
   10:	ldc	#5; //String abc
   12:	invokevirtual	#6; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
   15:	aload_1
   16:	invokevirtual	#6; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
   19:	ldc	#7; //String def
   21:	invokevirtual	#6; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
   24:	bipush	47
   26:	invokevirtual	#8; //Method java/lang/StringBuilder.append:(I)Ljava/lang/StringBuilder;
   29:	invokevirtual	#9; //Method java/lang/StringBuilder.toString:()Ljava/lang/String;
   32:	astore_2
   33:	getstatic	#10; //Field java/lang/System.out:Ljava/io/PrintStream;
   36:	aload_2
   37:	invokevirtual	#11; //Method java/io/PrintStream.println:(Ljava/lang/String;)V
   40:	return

}

从上述代码中看,编译器确实创建了一个StringBuilder对象。
但是,这并不能因此就说明可以随意的使用String对象。下面又举了个例子:

package com.linc.TestString;

public class StringAndBuilder {
	public String implicit(String[] fields)
	{
		String result="";
		for(int i=0;i<fields.length;++i)
		{
			result+=fields[i];
		}
		return result;
	}
	
	public String explicit(String[] fields)
	{
		StringBuilder result=new StringBuilder();
		for(int i=0;i<fields.length;++i)
		{
			result.append(fields[i]);
		}
		return result.toString();
	}
}

反编译一下:
[linc@localhost TestString]$ javac StringAndBuilder.java 
[linc@localhost TestString]$ javap -c StringAndBuilder

Compiled from "StringAndBuilder.java"
public class com.linc.TestString.StringAndBuilder extends java.lang.Object{
public com.linc.TestString.StringAndBuilder();
  Code:
   0:	aload_0
   1:	invokespecial	#1; //Method java/lang/Object."<init>":()V
   4:	return

public java.lang.String implicit(java.lang.String[]);
  Code:
   0:	ldc	#2; //String 
   2:	astore_2
   3:	iconst_0
   4:	istore_3
   5:	iload_3
   6:	aload_1
   7:	arraylength
   8:	if_icmpge	38
   11:	new	#3; //class java/lang/StringBuilder
   14:	dup
   15:	invokespecial	#4; //Method java/lang/StringBuilder."<init>":()V
   18:	aload_2
   19:	invokevirtual	#5; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
   22:	aload_1
   23:	iload_3
   24:	aaload
   25:	invokevirtual	#5; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
   28:	invokevirtual	#6; //Method java/lang/StringBuilder.toString:()Ljava/lang/String;
   31:	astore_2
   32:	iinc	3, 1
   35:	goto	5
   38:	aload_2
   39:	areturn

public java.lang.String explicit(java.lang.String[]);
  Code:
   0:	new	#3; //class java/lang/StringBuilder
   3:	dup
   4:	invokespecial	#4; //Method java/lang/StringBuilder."<init>":()V
   7:	astore_2
   8:	iconst_0
   9:	istore_3
   10:	iload_3
   11:	aload_1
   12:	arraylength
   13:	if_icmpge	30
   16:	aload_2
   17:	aload_1
   18:	iload_3
   19:	aaload
   20:	invokevirtual	#5; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
   23:	pop
   24:	iinc	3, 1
   27:	goto	10
   30:	aload_2
   31:	invokevirtual	#6; //Method java/lang/StringBuilder.toString:()Ljava/lang/String;
   34:	areturn

}

注意到implicit方法,从第8行到第35行构成了一个循环体。StringBuilder是在循环体内构造的,也就是说,每经过一次循环,就会创建一个新的StrinBuilder对象。
再看explicit方法,循环部分的代码更简短、简单,而且只生成了一个StrinBuilder对象。


结论:
当为一个类编写toString()方法时,如果操作比较简单,就可以信赖编译器,它会为你合理的构造最终的字符串结果。如果使用了循环,那么最好自己创建一个StringBuilder对象。
如果拿不准该用那种方式,就用javap来分析你的程序吧!


另外,linc之前还翻译了一段小文章,是讲String、StringBuffer和StringBuilder之间的区别的:http://blog.csdn.net/lincyang/article/details/6333041

  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值