String、StringBuffer和StringBuild的区别

  • public class Test1 {
  • public static void stringReplace (String text) {
  • text = text.replace(‘j‘,‘i‘) ;
  • System.out.println(text) ;
  • }
  • public static void stringBufferReplace(StringBuffer text) {
  • text = text.append("c") ;
  • System.out.println(text) ;
  • }
  • public static void main(String args[]) {
  • String stringtext = new String("java") ;
  • StringBuffer buffertext = new StringBuffer("java") ;
  • stringReplace(stringtext) ;
  • stringBufferReplace(buffertext) ;
  • System.out.println(stringtext+"/t"+buffertext) ;
  • }
  • }

输出的结果是:

iava

javac

java  javac

这是因为第七行text = text.append ("C"),append方法会改变text中的值,而text与textBuffer指向的地址是相同的。因此会打印javaC

再举个例子:

String a = "a"; //假设a指向地址0x0001

a = "b";//重新赋值后a指向地址0x0002,但0x0001地址中保存的"a"依旧存在,但已经不再是a所指向的。

因此String的操作都是改变赋值地址而不是改变值操作

String 类型和 StringBuffer 类型的主要性能区别其实在于 String 是不可变的对象(为什么?问问 Java 的设计者吧,为什么 String 不是原生类型呢?)因此在每次对 String 类型进行改变的时候其实都等同于生成了一个新的 String 对象,然后将指针指向新的 String 对象,所以经常改变内容的字符串最好不要用 String ,因为每次生成对象都会对系统性能产生影响,特别当内存中无引用对象多了以后, JVM 的 GC 就会开始工作,那速度是一定会相当慢的。这里尝试举个不是很恰当的例子:

String S1 = “abc”; For(int I = 0 ; I < 10000 ; I ++) // For 模拟程序的多次调用 { S1 + = “def”; S1 = “abc”; }

如果是这样的话,到这个 for 循环完毕后,如果内存中的对象没有被 GC 清理掉的话,内存中一共有 2 万多个了,惊人的数目,而如果这是一个很多人使用的系统,这样的数目就不算很多了,所以大家使用的时候一定要小心。

而如果是使用 StringBuffer 类则结果就不一样了,每次结果都会对 StringBuffer 对象本身进行操作,而不是生成新的对象,再改变对象引用。所以在一般情况下我们推荐使用 StringBuffer ,特别是字符串对象经常改变的情况下。而在某些特别情况下, String 对象的字符串拼接其实是被 JVM 解释成了 StringBuffer 对象的拼接,所以这些时候 String 对象的速度并不会比 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 居然速度上根本一点都不占优势。其实这是 JVM 的一个把戏,在 JVM 眼里,这个

String S1 = “This is only a” + “ simple” + “test”; 其实就是: String S1 = “This is only a simple test”; 所以当然不需要太多的时间了。但大家这里要注意的是,如果你的字符串是来自另外的 String 对象的话,速度就没那么快了,譬如:

String S2 = “This is only a”; String S3 = “ simple”; String S4 = “ test”; String S1 = S2 +S3 + S4;

这时候 JVM 会规规矩矩的按照原来的方式去做, S1 对象的生成速度就不像刚才那么快了,一会儿我们可以来个测试作个验证。

由此我们得到第一步结论: 在大部分情况下 StringBuffer > String

而 StringBuilder 跟他们比又怎么样呢?先简单介绍一下, StringBuilder 是 JDK5.0 中新增加的一个类,它跟 StringBuffer 的区别看下面的介绍(来源 JavaWorld ):

Java.lang.StringBuffer 线程安全的可变字符序列。类似于 String 的字符串缓冲区,但不能修改。可将字符串缓冲区安全地用于多个线程。可以在必要时对这些方法进行同步,因此任意特定实例上的所有操作就好像是以串行顺序发 生的,该顺序与所涉及的每个线程进行的方法调用顺序一致。

每个字符串缓冲区都有一定的容量。只要字符串缓冲区所包含的字符序列的长度没有超出此容量,就无需分配新的内部缓冲区数组。如果内部缓冲区溢出,则此容量 自动增大。从 JDK 5.0 开始,为该类增添了一个单个线程使用的等价类,即 StringBuilder 。与该类相比,通常应该优先使用 StringBuilder 类,因为它支持所有相同的操作,但由于它不执行同步,所以速度更快。

但是如果将 StringBuilder 的实例用于多个线程是不安全的。需要这样的同步,则建议使用 StringBuffer 。

这样说估计大家都能明白他们之间的区别了,那么下面我们再做一个一般性推导:

在大部分情况下 StringBuilder > StringBuffer

因此,根据这个不等式的传递定理: 在大部分情况下 StringBuilder > StringBuffer > String

既然有这样的推导结果了,我们做个测试验证一下:

测试代码如下:

public class testssb {

/** Creates a new instance of testssb */ final static int ttime = 10000;// 测试循环次数 public testssb() { }

public void test(String s){ long begin = System.currentTimeMillis(); for(int i=0;i<ttime;i++){ s += "add"; } long over = System.currentTimeMillis(); System.out.println(" 操作 "+s.getClass().getName()+" 类型使用的时间为: " + (over - begin) + " 毫秒 " ); }

public void test(StringBuffer s){ long begin = System.currentTimeMillis(); for(int i=0;i<ttime;i++){ s.append("add"); } long over = System.currentTimeMillis(); System.out.println(" 操作 "+s.getClass().getName()+" 类型使用的时间为: " + (over - begin) + " 毫秒 " ); }

public void test(StringBuilder s){ long begin = System.currentTimeMillis(); for(int i=0;i<ttime;i++){ s.append("add"); } long over = System.currentTimeMillis(); System.out.println(" 操作 "+s.getClass().getName()+" 类型使用的时间为: " + (over - begin) + " 毫秒 " ); }

// 对 String 直接进行字符串拼接的测试 public void test2(){ String s2 = "abadf"; long begin = System.currentTimeMillis(); for(int i=0;i<ttime;i++){ String s = s2 + s2 + s2 ; } long over = System.currentTimeMillis(); System.out.println(" 操作字符串对象引用相加类型使用的时间为: " + (over - begin) + " 毫秒 " ); }

public void test3(){ long begin = System.currentTimeMillis(); for(int i=0;i<ttime;i++){ String s = "abadf" + "abadf" + "abadf" ; } long over = System.currentTimeMillis(); System.out.println(" 操作字符串相加使用的时间为: "+ (over - begin) + " 毫秒 " ); }

public static void main(String[] args){ String s1 ="abc"; StringBuffer sb1 = new StringBuffer("abc"); StringBuilder sb2 = new StringBuilder("abc");

testssb t = new testssb(); t.test(s1); t.test(sb1); t.test(sb2); t.test2(); t.test3(); } }

以上代码在 NetBeans 5.0 IDE/JDK1.6 上编译通过,循环次数 ttime 为 10000 次的测试结果如下: 操作 java.lang.String 类型使用的时间为: 4392 毫秒 操作 java.lang.StringBuffer 类型使用的时间为: 0 毫秒 操作 java.lang.StringBuilder 类型使用的时间为: 0 毫秒 操作字符串对象引用相加类型使用的时间为: 15 毫秒 操作字符串相加使用的时间为: 0 毫秒

好像还看不出 StringBuffer 和 StringBuilder 的区别,把 ttime 加到 30000 次看看: 操作 java.lang.String 类型使用的时间为: 53444 毫秒 操作 java.lang.StringBuffer 类型使用的时间为: 15 毫秒 操作 java.lang.StringBuilder 类型使用的时间为: 15 毫秒 操作字符串对象引用相加类型使用的时间为: 31 毫秒 操作字符串相加使用的时间为: 0 毫秒

StringBuffer 和 StringBuilder 的性能上还是没有太大的差异,再加大到 100000 看看,这里就不加入对 String 类型的测试了,因为对 String 类型这么大数据量的测试会很慢滴…… 操作 java.lang.StringBuffer 类型使用的时间为: 31 毫秒 操作 java.lang.StringBuilder 类型使用的时间为: 16 毫秒

能看出差别了,但其中有多次的测试结果居然是 StringBuffer 比 StringBuilder 快,再加大一些到 1000000 看看(应该不会当机吧?): 操作 java.lang.StringBuffer 类型使用的时间为: 265 毫秒 操作 java.lang.StringBuilder 类型使用的时间为: 219 毫秒

有些少区别了,而且结果很稳定,再大点看看, ttime = 5000000 :

······ Exception in thread "main" java.lang.OutOfMemoryError: Java heap space ······

呵呵,算了,不去测试了,基本来说都是在性能上都是 StringBuilder > StringBuffer > String 的了。

总结: String StringBuffer StringBuilder 对比 1.jdk版本支持 StringBuilder JDK1.5以后版本支持 2.线程安全 StringBuffer 线程安全 StringBuilder 线程不安全 Java.lang.StringBuffer 线程安全的可变字符序列。类似于 String 的字符串缓冲区,但不能修改。可将字符串缓冲区安全地用于多个线程。可以在必要时对这些方法进行同步,因此任意特定实例上的所有操作就好像是以串行顺序发 生的,该顺序与所涉及的每个线程进行的方法调用顺序一致。 每个字符串缓冲区都有一定的容量。只要字符串缓冲区所包含的字符序列的长度没有超出此容量,就无需分配新的内部缓冲区数组。如果内部缓冲区溢出,则此容量 自动增大。从 JDK 5.0 开始,为该类增添了一个单个线程使用的等价类,即 StringBuilder 。与该类相比,通常应该优先使用 StringBuilder 类,因为它支持所有相同的操作,但由于它不执行同步,所以速度更快。 但是如果将 StringBuilder 的实例用于多个线程是不安全的。需要这样的同步,则建议使用 StringBuffer 。 3.速度 一般情况下,速度从快到慢:StringBuilder>StringBuffer>String.当需要在循环中多次使用字符串拼接时,建 议使用StringBuilder或StringBuffer.当数量级在百万级(这里可能不准确)时,StringBuilder的速度会体现出来. 4.参数传递问题 方法a(){String str;....;b(str);//调用b方法,处理str} 方法b(String str){str="test";} 此时,方法a中的str并不会改变,因为str="test"时,str重新被分配了内存

时间: 2024-12-23 06:30:32

String、StringBuffer和StringBuild的区别的相关文章

【Java】String,StringBuffer与StringBuilder的区别??

String 字符串常量StringBuffer 字符串变量(线程安全)StringBuilder 字符串变量(非线程安全) 简要的说, String 类型和 StringBuffer 类型的主要性能区别其实在于 String 是不可变的对象, 因此在每次对 String 类型进行改变的时候其实都等同于生成了一个新的 String 对象,然后将指针指向新的 String 对象,所以经常改变内容的字符串最好不要用 String ,因为每次生成对象都会对系统性能产生影响,特别当内存中无引用对象多了以

String,StringBuffer与StringBuilder的区别,线程安全,非线程安全

String,StringBuffer与StringBuilder的区别?? 转载地址:http://blog.csdn.net/rmn190/article/details/1492013 另外:StringBuilder的实现与技巧 : http://lixianhuei.cnblogs.com/archive/2005/12/27/305708.html 对线程安全 ,非线程安全的讨论: 怎么理解Stringbuffer 是线程安全的 stringbuilder是线程不安全的? http:

String,StringBuffer与StringBuilder的区别?-转

String 字符串常量StringBuffer 字符串变量(线程安全)StringBuilder 字符串变量(非线程安全) 简 要的说, String 类型和 StringBuffer 类型的主要性能区别其实在于 String 是不可变的对象, 因此在每次对 String 类型进行改变的时候其实都等同于生成了一个新的 String 对象,然后将指针指向新的 String 对象,所以经常改变内容的字符串最好不要用 String ,因为每次生成对象都会对系统性能产生影响,特别当内存中无引用对象多了

String,StringBuffer与StringBuilder的区别??

String 字符串常量StringBuffer 字符串变量(线程安全)StringBuilder 字符串变量(非线程安全) 简 要的说, String 类型和 StringBuffer 类型的主要性能区别其实在于 String 是不可变的对象, 因此在每次对 String 类型进行改变的时候其实都等同于生成了一个新的 String 对象,然后将指针指向新的 String 对象,所以经常改变内容的字符串最好不要用 String ,因为每次生成对象都会对系统性能产生影响,特别当内存中无引用对象多了

(转)String,StringBuffer与StringBuilder的区别??

String 字符串常量StringBuffer 字符串变量(线程安全)StringBuilder 字符串变量(非线程安全) 简要的说, String 类型和 StringBuffer 类型的主要性能区别其实在于 String 是不可变的对象, 因此在每次对 String 类型进行改变的时候其实都等同于生成了一个新的 String 对象,然后将指针指向新的 String 对象,所以经常改变内容的字符串最好不要用 String ,因为每次生成对象都会对系统性能产生影响,特别当内存中无引用对象多了以

String StringBuffer StringBuilder 之间的区别

StringBuffer与StringBuilder的区别: StringBuffer是jdk1.0版本出来的,线程安全,效率低 StringBuilder是jdk1.5版本出来的,线程不安全,效率高 String 与StringBuffer,StringBuilder 啷两个之间的区别: String是一个不可变的字符序列 StringBuffer,StringBuilder 是可变的字符序列

JAVA String,StringBuffer与StringBuilder的区别??

String 字符串常量StringBuffer 字符串变量(线程安全)StringBuilder 字符串变量(非线程安全) 简要的说, String 类型和 StringBuffer 类型的主要性能区别其实在于 String 是不可变的对象, 因此在每次对 String 类型进行改变的时候其实都等同于生成了一个新的 String 对象,然后将指针指向新的 String 对象,所以经常改变内容的字符串最好不要用 String ,因为每次生成对象都会对系统性能产生影响,特别当内存中无引用对象多了以

String,StringBuffer与StringBuilder的区别,希望有帮助

String 字符串常量StringBuffer 字符串变量(线程安全)StringBuilder 字符串变量(非线程安全) 简要的说, String 类型和 StringBuffer 类型的主要性能区别其实在于 String 是不可变的对象, 因此在每次对 String 类型进行改变的时候其实都等同于生成了一个新的 String 对象,然后将指针指向新的 String 对象,所以经常改变内容的字符串最好不要用 String ,因为每次生成对象都会对系统性能产生影响,特别当内存中无引用对象多了以

(转)String,StringBuffer与StringBuilder的区别

String 字符串常量(线程安全)StringBuffer 字符串变量(线程安全)StingBuilder字符串变量(非线程安全) 简要的说, String 类型和 StringBuffer 类型的主要性能区别其实在于 String 是不可变的对象, 因此在每次对 String 类型进行改变的时候其实都等同于生成了一个新的 String 对象,然后将指针指向新的 String 对象,所以经常改变内容的字符串最好不要用 String ,因为每次生成对象都会对系统性能产生影响,特别当内存中无引用对