String、StringBuffer与StringBuilder之间区别

本文详细对比了Java中String、StringBuffer和StringBuilder三个类的特点及适用场景,并通过实验数据直观展示了它们在性能上的差异。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

java中String、StringBuffer、StringBuilder是编程中经常使用的字符串类,他们之间的区别也是经常在面试中会问到的问题。现在总结一下,看看他们的不同与相同。

它们的异同点:
* 1) 都是 final 类, 都不允许被继承;
* 2) String 长度是不可变的, StringBuffer、StringBuilder 长度是可变的;
* 3) StringBuffer 是线程安全的, StringBuilder 不是线程安全的。

String VS StringBuffer


String 类型和StringBuffer的主要性能区别:String是不可变的对象, 因此在每次对String 类型进行改变的时候,都会生成一个新的 String 对象,然后将指针指向新的 String 对象,所以经常改变内容的字符串最好不要用 String ,因为每次生成对象都会对系统性能产生影响,特别当内存中无引用对象多了以后, JVM 的 GC 就会开始工作,性能就会降低。
使用 StringBuffer 类时,每次都会对 StringBuffer 对象本身进行操作,而不是生成新的对象并改变对象引用。所以多数情况下推荐使用 StringBuffer ,特别是字符串对象经常改变的情况下。
在某些特别情况下, String 对象的字符串拼接其实是被 Java Compiler 编译成了 StringBuffer 对象的拼接,所以这些时候 String 对象的速度并不会比 StringBuffer 对象慢,例如:

String s1 = “This is only a” + “ simple” + “ test”;
StringBuffer Sb = new StringBuilder(“This is only a”).append(“ simple”).append(“ test”);

生成 String s1对象的速度并不比 StringBuffer慢。其实在Java Compiler里,自动做了如下转换:
Java Compiler直接把上述第一条语句编译为:

String s2 = “This is only a”;  
String s3 = “ simple”;  
String s4 = “ test”;  
String s1 = s2 + s3 + s4;

这时候,Java Compiler会规规矩矩的按照原来的方式去做,String的concatenation(即+)操作利用了StringBuilder(或StringBuffer)的append方法实现,此时,对于上述情况,若s2,s3,s4采用String定义,拼接时需要额外创建一个StringBuffer(或StringBuilder),之后将StringBuffer转换为String;若采用StringBuffer(或StringBuilder),则不需额外创建StringBuffer。

StringBuilder

StringBuilder是5.0新增的。此类提供一个与 StringBuffer 兼容的 API,但不保证同步。该类被设计用作 StringBuffer 的一个简易替换,用在字符串缓冲区被单个线程使用的时候(这种情况很普遍)。如果可能,建议优先采用该类,因为在大多数实现中,它比 StringBuffer 要快。两者的方法基本相同。

使用策略

1) 基本原则:如果要操作少量的数据,用String ;单线程操作大量数据,用StringBuilder ;多线程操作大量数据,用StringBuffer。

2) 不要使用String类的”+”来进行频繁的拼接,因为那样的性能极差的,应该使用StringBuffer或StringBuilder类,这在Java的优化上是一条比较重要的原则。

3) StringBuilder一般使用在方法内部来完成类似”+”功能,因为是线程不安全的,所以用完以后可以丢弃。StringBuffer主要用在全局变量中。

接下来,看看测试代码:

package test;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

public class StringTest {
	private static final String base = " base string. ";
	private static final int count = 2000000;

	public static void stringTest() {
		long begin, end;
		begin = System.currentTimeMillis();
		String test = new String(base);
		for (int i = 0; i < count / 100; i++) {
			test = test + " add ";
		}
		end = System.currentTimeMillis();
		System.out.println((end - begin) + " millis has elapsed when used String. ");
	}

	public static void stringBufferTest() {
		long begin, end;
		begin = System.currentTimeMillis();
		StringBuffer test = new StringBuffer(base);
		for (int i = 0; i < count; i++) {
			test = test.append(" add ");
		}
		end = System.currentTimeMillis();
		System.out.println((end - begin) + " millis has elapsed when used StringBuffer. ");
	}

	public static void stringBuilderTest() {
		long begin, end;
		begin = System.currentTimeMillis();
		StringBuilder test = new StringBuilder(base);
		for (int i = 0; i < count; i++) {
			test = test.append(" add ");
		}
		end = System.currentTimeMillis();
		System.out.println((end - begin) + " millis has elapsed when used StringBuilder. ");
	}

	public static String appendItemsToStringBuiler(List list) {
		StringBuilder b = new StringBuilder();
		long starttime = System.currentTimeMillis();
		for (Iterator i = list.iterator(); i.hasNext();) {
			b.append(i.next()).append(" ");
		}
		long endtime = System.currentTimeMillis();
		System.out.println("builder cost:"
                + (endtime - starttime) + " millis");  
		return b.toString();
	}

	public static void addToStringBuilder() {
		List list = new ArrayList();
		list.add(" I ");
		list.add(" play ");
		list.add(" basketball ");
		list.add(" football ");
		list.add(" and ");
		list.add(" guitar ");
		list.add(" piano ");
		System.out.println(appendItemsToStringBuiler(list));
	}

	public static String appendItemsToStirngBuffer(List list) {
		StringBuffer b = new StringBuffer();
		long starttime = System.currentTimeMillis();
		for (Iterator i = list.iterator(); i.hasNext();) {
			b.append(i.next()).append(" ");
		}
		long endtime = System.currentTimeMillis();
		System.out.println("buffer cost:"  
                + (endtime - starttime) + " millis");
		return b.toString();
	}

	public static void addToStringBuffer() {
		List list = new ArrayList();
		list.add(" I ");
		list.add(" play ");
		list.add(" basketball ");
		list.add(" football ");
		list.add(" and ");
		list.add(" guitar ");
		list.add(" piano ");
		System.out.println(appendItemsToStirngBuffer(list));
	}

	public static void main(String[] args) {
		stringTest();
		stringBufferTest();
		stringBuilderTest();
		addToStringBuffer();
		addToStringBuilder();
	}

}

结果如下:

925 millis has elapsed when used String. 
82 millis has elapsed when used StringBuffer. 
32 millis has elapsed when used StringBuilder. 
buffer cost:0 millis
 I   play   basketball   football   and   guitar   piano  
builder cost:0 millis
 I   play   basketball   football   and   guitar   piano  


从上面的结果来看,这三个类在单线程程序中的性能差别一目了然,采用String对象时,即使运行次数仅是采用其他对象的1/100,其执行时间仍然比其他对象高出 11+ 倍以上;而采用StringBuffer对象和采用StringBuilder对象的差别也比较明显,前者是后者的2.5倍左右。由此可见,如果我们的程序是在单线程下运行,或者是不必考虑到线程同步问题,我们应该优先使用StringBuilder类;当然,如果要保证线程安全,自然非StringBuffer莫属了。 除了对多线程的支持不一样外,这两个类的使用几乎没有任何差别,上面的例子就是个很好的说明。
appendItemsToStringBuiler和appendItemsToStirngBuffer两个方法除了采用的对象分别为StringBuilder和StringBuffer外,其他完全相同,而效果也完全相同。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值