目录
String
StringBuffer
StringBuilder
总结
ps:昨天在讨论完String的不可变性之后突然想要做一份总结笔记,总结一下String、StringBuffer、StringBuilder的区别
String
String是Java中的基础类,提供了各种构造和对字符串的基本操作,并且因为它的不可变性,对于字符串的拼接、截取字符串等操作,都会产生新的String对象,由于字符串操作的普遍性,所以相关的操作的效率往往对程序的性能有明显影响;
那么明显在哪里呢?我们来做一个实验,我们首先创建一个简单的字符串,如果要将字符串进行凭接起来,我们来观察一下,以下代码是凭接1000个字符后的运行时间
public static void main (String[] args) {
String str=new String("1~1000的数字有:");
long time=System.currentTimeMillis();
for (int i = 1 ; i <= 1000 ; i++) {
str+=i;
}
long lasttime=System.currentTimeMillis();
System.out.println(lasttime-time);
}
我们可以看到运行时间为5毫秒,我们再用测试一下1w个数据
public static void main (String[] args) {
String str=new String("1~1_0000的数字有:");
long time=System.currentTimeMillis();
for (int i = 1 ; i <= 1_0000 ; i++) {
str+=i;
}
long lasttime=System.currentTimeMillis();
System.out.println(lasttime-time);
}
我们可以看到,稍等了一会儿才出来,博主又测试了一下10_0000个数据,需要用的时间为20秒左右
我们可以发现,数据拼接的越长需要的时间越长,这是为什么呢?
我们String凭接的时候会产生大量的常量,首先是凭接前我们会产生一个常量,拼接后又会重新产生一个常量, 如此反反复复进行开辟,既造成了大量的内存浪费,大量的时间也被浪费掉了,不停的创建对象是程序低效的一个重要原因。那么相同的字符串值能否在堆中只创建一个String对象那。显然拘留字符串能够做到这一点,除了程序中的字符串常量会被JVM自动创建拘留字符串之外,调用String的intern()方法也能做到这一点。当调用intern()时,如果常量池中已经有了当前String的值,那么返回这个常量指向拘留对象的地址。如果没有,则将String值加入常量池中,并创建一个新的拘留字符串对象。
这边也有一个反编译的解读,打开方式如下,首先找到class文件所在的位置
解读大概如下
那么我们对于这种行为有什么更好的解决方法吗?
此时我们就诞生了StringBuffer、Stringbuilder
StringBuffer
StringBuffer是为解决上面提到拼接产生太多中间对象的问题而提供的一个类,我们可以用 append 或者 add 方法,把字符串添加到已有序列的末尾或者指定位置。本质是一个线程安全的可修改字符序列,它保证了线程安全(不会常见常量)
我们可以来看一下StringBuffer的源码
大部分方法都是sychronized(英译同步进行)所修饰的,保证线程安全
那么有的童鞋就疑惑了,什么是线程安全呢?下面用一张图解读
今天我们帅气的博主在公共卫生间上厕所,然后我们如果将卫生间门锁起来,别人就不会再进来了,但是如果我不去将们锁起来,别人在不知道情况下就会推门而进……线程安全就是那把锁,我们上锁以及开锁也是需要时间的,但是能保证厕所一次只会容纳一个人,也就是只有一个进程在运行,如此就是线程安全
虽然StringBuffer可以保证线程安全,但也随之带来了额外的性能开销,所以除非有线程安全的需要,不然还是推荐使用它的后继者,也就是 StringBuilder
StringBuilder
StringBuilder是 Java 1.5 中新增的,在能力上和StringBuffer没有本质区别,但是它去掉了线程安全的部分,有效减小了开销,是绝大部分情况下进行字符串拼接的首选。
还是可以观察一下源码
总结
(1)如果要操作少量的数据用 String;
(2)多线程操作字符串缓冲区下操作大量数据 StringBuffer;
(3)单线程操作字符串缓冲区下操作大量数据 StringBuilder。
StringBuffer和StringBuilder的区别
StringBuffer是在保证线程安全的环境下运行的,相比更加的安全,StringBuilder不会考虑线程安全的问题,但是运行速度>StringBuffer,毕竟加锁和解锁也是需要时间的嘛