先来看以下问题,以下代码创建了几个对象?
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()); } }
相关推荐
String StringBuffer和StringBuilder 区别之源码解析 从源码角度简单对它们之间的区别进行了验证
String,StringBuffer,StringBuilder区别。几乎所有的应用开发都离不开操作字符串,理解字符串的设计和实现以及相关 工具如拼接类的使用,对写出高质量代码是非常有帮助的
String、StringBuilder和StringBuffer的区别 String、StringBuilder和StringBuffer的区别 String、StringBuilder和StringBuffer的区别
StringBuffer:字符创变量 StringBuilder:字符创变量 从上面的名字可以看到,String是“字符创常量”,也就是不可改变的对象。对于这句话的理解你可能会产生这样一个疑问 ,比如这段代码:
下面小编就为大家带来一篇浅谈java中String StringBuffer StringBuilder的区别。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
介绍了String、StringBuffer、StringBuilder的使用方法,以及理论知识
String及StringBuffer和StringBuilder的区别
String ,StringBuffer与StringBuilder的区别
String、StringBuffer 和 StringBuilder 的区别 碎碎念 简单认识这三个对象 String StringBuffer StringBuilder 深入理解 String、StringBuilder、StringBuffer 从设计角度理解 String StringBuilder StringBuffer ...
简单的介绍了String、StringBuffer和StringBuilder的区别
stringbuilder用法 String、StringBuilder、StringBuffer 用法比较String、StringBuilder、StringBuffer 用法比较String、StringBuilder、StringBuffer 用法比较String、StringBuilder、StringBuffer 用法比较String...
目录StringStringBuffer与StringBuilder总结 String ...StringBuffer与StringBuilder 这两者基本相似,都是可变字符串对象,主要区别为线程是否安全。 总结 最后,引用菜鸟教程下的总结以及相关评论: S
主要介绍了java 中String和StringBuffer与StringBuilder的区别及使用方法的相关资料,在开发过程中经常会用到String 这个类进行操作,需要的朋友可以参考下
String、StringBuilder以及StringBuffer的区别
string,stringbuffer,stringbuilder
string,stringBuffer,stringBuilder
java中String、StringBuffer、StringBuilder是编程中经常使用的字符串类,他们之间有什么区别呢?下面小编给大家总结了Java中String、StringBuffer、StringBuilder的区别详解,需要的朋友参考下吧
关于String、StringBuilder、StringBuffer的本质区别,
主要介绍了Java 中 String,StringBuffer 和 StringBuilder 的区别及用法的相关资料,需要的朋友可以参考下
Java中String,StringBuffer与StringBuilder的区别和用法。