String,StringBuffer,StringBuilder的区别这个问题几乎是面试必问的题,这里做了一些总结:
1.先来分析一下这三个类之间的关系(都是通过字符数组来实现的)
乍一看它们都是用于处理字符串的java类,而且长得也都差不多,相信肯定有人会以为StringBuffer和StringBuilder都是继承自String这个类,即认为String类是其他两个类的超类。这种想法似乎很合理,但其实是不对的,事实上StringBuffer和StringBuilder确实是继承自某个类,但是这个类并不是String,至于是哪个类呢?我i们来看一下JDK源码:
StringBuffer类部分源码
StringBuilder类部分源码
String类部分源码
看到这里,这三个类的关系基本清晰:StringBuffer和StringBuilder都继承自AbstractStringBuilder这个类,而AbstractStringBuilder和String都继承自Object这个类(Object是所有java类的超类)。所以这三个类之间的关系可以大致表示为:
关于AbstractStringBuilder这个类,本人只在JDK1.8中的java.lang包下找到了,而在JDK1.6和JDK1.7中均未找到,似乎是1.8版本新加上去的,各位看官可以试着找找。
2.String是不可变类,而StringBuffer, StringBuilder是可变类
我们查看这三个类的源码,发现String类没有append()、delete()、insert()这三个成员方法,而StringBuffer和StringBuilder都有这些方法,这就很容易理解了(这里就不粘代码了,大家可以找源码看看)。所以我们可以归纳如下:
String —— 字符串常量;
StringBuffer —— 字符串变量;
StringBuilder —— 字符串变量。
这里再补充一点:从源代码仔细追究下去,可以发现StringBuffer和StringBuilder中的append、delete、insert这几个成员方法都是通过System类的arraycopy方法来实现的,即将原数组复制到目标数组。至于System类的定义和用法,笔者将在之后的文章进行介绍。
3.再来说一下执行速度
在执行速度上,String < StringBuffer < Stringbuilder 。
3.1 String < StringBuffer
这是因为String类是不可变的,即字符串常量,所以每次对 String 类型进行改变的时候其实都等同于生成了一个新的 String 对象,然后将指针指向新的 String 对象。这就会对程序运行产生很大的影响,因为当内存中的无引用对象多了以后,JVM的GC进程就会进行垃圾回收,这个过程会耗费很长一段时间,因此经常改变内容的字符串最好不要用 String类的对象。而如果是使用 StringBuffer 类则结果就不一样了,每次结果都会对 StringBuffer 对象本身进行操作,而不是生成新的对象,再改变对象引用。所以在一般情况下我们推荐使用 StringBuffer ,特别是字符串对象经常改变的情况下。
但是在某些特殊情况下, String 对象的字符串拼接其实是被 JVM 解释成了 StringBuffer 对象的拼接,所以这些时候 String 对象的速度并不会比 StringBuffer 对象慢,而特别是以下的字符串对象生成中, String 运行速度是远要比 StringBuffer 快的:
但是如果要拼接的字符串来自于不同的String对象的话,那结果就不一样了:
这时候使用StringBuffer的运行速度更快,而这是我们编程时的大部分情况。
3.2 StringBuffer < StringBuilder
这个结论的原因涉及到线程安全和非线程安全,将在下一节详细介绍。