String和StringBuilder效率不同的原理

Posted blairwaldorf

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了String和StringBuilder效率不同的原理相关的知识,希望对你有一定的参考价值。

在做实验的时候,中间有一个任务为一个图的toString.,用来打印每条边每个点的信息。

其中用到了字符串的链接 我当时用的是String 的 “+”操作,

但是图怎么也无法输出,因为有三十多万条边,在大量的字符串的拼接的时候,“+”特别耗时间和内存。

然后我通过网上查找,选择用StringBuilder的方法解决了这个问题。

StringBuilder str = new StringBuilder();
str.append("lalalallal");
for(int i=0;i<5;i++)
    str.append("lalalallal");
System.out.println(str);

但是当时也没有仔细想原理是什么,而后来复习到mutable(可变数据类型)和immutable(不可变数据类型)的时候才仔细思考了这个问题,String和StringBuilder正好是它们的典型代表。

String是immutable的变量,一旦被创建,它的值就不能被改变。注意:改变一个变量是将该变量指向另一个值的存储空间,二改变一个变量的值是将该变量当前指向的值的存储空间写入一个新的值。

通过分析snapshot diagram我们发现,当string "+"的时候,是新建了一个String空间然后将原来变量的指向这个空间。原来的String被废弃只能等待着被垃圾回收。又通过后来学习的垃圾回收的机制我们知道这是非常浪费资源的,当然也有其安全性。

技术分享图片

而StringBuilder则是直接修改,所以执行起来很快。

 

技术分享图片

其实这只是区别的一部分,因为这种机制的不同还带来了很多很多潜在的bug

 

比如:

List<String> list =new LinkedList<>();
String s1 = new String("aaa");
list.add(s1);
System.out.println(list.contains(s1));//true
s1=s1.concat("q");
System.out.println(list.contains(s1));//false

 奇怪的是,把s1加入到list之后,修改了s1,此时s1就不包含在list里面了

通过snapshot diagram可以看见这种现象的原因。List是直接指向元素所在的空间,当修s1之后,s1的引用改变,此时s1指向的空间也已经改变,不再是从前的s1了。

 技术分享图片

比如:

		String s="ab";
		String t=s;
		s=s+"c";
		System.out.println(t);//ab

 因为虽然t指向了s,但是s改变之后,t指向的值并没有改变,因为此时s是重新指向了新的区域。

技术分享图片

因此,我们在选择合适的类型的时候,要仔细考虑的有安全、效率、还要多个引用带来的潜在的bug

 




以上是关于String和StringBuilder效率不同的原理的主要内容,如果未能解决你的问题,请参考以下文章

StringBuffer和StringBuilder

String 类详解

String,StringBuilder 和StringBuffer区别

String,StringBuffer,StringBuilder效率优先关系说明

StringBuilder类与string类的区别

String 和 StringBuilder