String, StringBuffer, StringBuilder的区别

先来看以下问题,以下代码创建了几个对象?

 

String s1=new String("abc");

 

 

网上比较流行的说法是创建了两个对象:字符串对象abc和引用对象s1。这种说法十分模糊,什么是引用对象?s1究竟是引用还是对象?

 

正确的说法应该是s1是引用了一个字符串对象的变量,通过s1可以操作其所引用的字符串对象。因此从某种意义上,可以把s1直接视为对象(可以把s1理解为一个指向字符串对象的指针,但建议不要这样理解,因为Java里没有指针的概念)

 

查看String的帮助文档可以知道,执行以上代码将创建一个字符串对象,此对象的内容将“复制”所传入的参数值,这里为字符串abc。很显然,必须先创建abc然后才能进行复制。那么是谁创建的abc呢?

 

在Java里,字符串值如“abc”被实现为常量。在使用abc时,首先JVM会查找内存看是否已存在字符串abc,如果不存在则创建字符串abc对象,在随后的使用中,字符串abc对象都不会被改变。因此abc可称为字符串常量

 

因此执行以上代码可以肯定的是将创建变量s1指向的字符串对象。而在执行此代码前,如果abc对象不存在,那么将先创建abc字符串常量对象,否则不会创建。

 

因为字符串实现为常量,如果所使用的字符串在内存里不存在,那么JVM需要先创建他们(即为其分配内存),这可能会比较影响性能,以下代码将会创建4个字符串常量对象,即包含4次分配内存的操作:

String s1="a";
String s2="b";
String s3="c";
String s4=s1+s2+s3;

 

为了解决以上问题,Java提供了StringBuffer类。在创建StringBuffer对象时,会为其分配一块内存缓冲区,用于存放需要拼接的字符串值。在缓冲区存满前都不会再次进行分配,进而提高性能。

 

StringBuilder与StringBuffer基本相同,不同点在于StringBuilder是非线程安全的,而StringBuffer是线程安全的。因此StringBuilder性能高于StringBuffer

 

以下使用TestNG对以上部分观点进行了测试

 

以下测试说明,如果字符串常量对象已存在,那么后续变量将直接引用此对象:

package com.bingo.practice;

import org.testng.Assert;
import org.testng.annotations.Test;

public class StringEqualTest {
	
	@Test
	public void test(){
		String s1=new String("abc");
		String s2=new String("abc");
		
		//s1,s2引用不同的字符串对象,但是其字符串值相同
		Assert.assertEquals(s1, s2);
		Assert.assertEquals(s1, "abc");
		Assert.assertNotSame(s1, s2);
		
		String s3="abc";
		String s4="abc";
		
		//s3, s4都引用字符串常量对象abc
		Assert.assertEquals(s3, s4);
		Assert.assertSame(s3, s4);
	}
}

 

以下测试拼接字符串的性能比较:StringBuilder>StringBuffer>String

package com.bingo.practice;

import org.testng.annotations.Test;

public class StringPerformanceTest {
	private static final int count=100000;
	
	@Test
	public void testStringBuilder(){
		StringBuilder b=new StringBuilder();
		for(int i=0;i<count;i++)
			b.append("a");
		System.out.println(b.toString());
	}
	
	@Test
	public void testStringBuffer(){
		StringBuffer s=new StringBuffer();
		for(int i=0;i<count;i++)
			s.append("a");
		System.out.println(s.toString());
	}	
	
	@Test
	public void testString(){
		String s="";
		for(int i=0;i<count;i++)
			s+="a";
		System.out.println(s);
	}	
}

 

测试结果如下:

 

以下测试线程安全,String,StringBuilder非线程安全(测试失败),StringBuffer线程安全(测试通过)

package com.bingo.practice;

import org.testng.Assert;
import org.testng.annotations.AfterClass;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;

public class StringTest {
	private String actualString;
	private String expectedString;
	
	@BeforeClass
	public void init(){
		this.actualString="";
		this.expectedString="";
		
		for(int i=0;i<10000;i++)
			expectedString+="a";
	}
	
	@Test(invocationCount=10000,threadPoolSize=10)
	public void test(){
		actualString+="a";
	}
	
	@AfterClass
	public void finish(){
		Assert.assertEquals(actualString, expectedString);
	}
}

 

 

package com.bingo.practice;

import org.testng.Assert;
import org.testng.annotations.AfterClass;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;

public class StringBuilderTest {
	private StringBuilder actualBuilder;
	private StringBuilder expectedBuilder;
	
	@BeforeClass
	public void init(){
		this.actualBuilder=new StringBuilder();
		this.expectedBuilder=new StringBuilder();
		
		for(int i=0;i<10000;i++)
			expectedBuilder.append("a");
	}
	
	@Test(invocationCount=10000,threadPoolSize=10)
	public void test(){
		actualBuilder.append("a");
	}
	
	@AfterClass
	public void finish(){
		Assert.assertEquals(actualBuilder.toString(), expectedBuilder.toString());
	}
}

 

 

package com.bingo.practice;

import org.testng.Assert;
import org.testng.annotations.AfterClass;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;

public class StringBufferTest {
	private StringBuffer actualBuffer;
	private StringBuffer expectedBuffer;
	
	@BeforeClass
	public void init(){
		this.actualBuffer=new StringBuffer();
		this.expectedBuffer=new StringBuffer();
		
		for(int i=0;i<10000;i++)
			expectedBuffer.append("a");
	}
	
	@Test(invocationCount=10000,threadPoolSize=10)
	public void test(){
		actualBuffer.append("a");
	}
	
	@AfterClass
	public void finish(){
		Assert.assertEquals(actualBuffer.toString(), expectedBuffer.toString());
	}
}

 

 

 

 

 

 

 

 

 

 

 

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值