你知道如何合理的使用String,StringBuilder,StringBuffer吗

《倚天屠龙记》里面张三丰教张无忌太极功夫的时候说了一句,你有九阳神功护体,学什么武功都会很快。可见一个人内力深厚,是多么重要。
我们学习编程也是一样,什么事情都要看问题的本质,而编程问题的大部分本质都在源码里面。

很多人浑浑噩噩写了多年程序,对什么时候该使用 String ,什么时候该使用 StringBuilder,什么场景用 StringBuffer ,还是模棱两可。
今天就从源码的角度帮大家总结一下三者各自的区别以及使用场景。

首先三者都是用于表示跟字符串相关操作的。String 是不可变的。StringBuilderStringBuffer是可变的。
String为 什么是不可变的,我在这篇博文里面已经说过了。
这里重点说一下 StringBuilderStringBuffer 为什么是可变的。
既然 StringBufferStringBuilder 都继承自抽象类 AbstractStringBuilder。那么我们就先来看一下 AbstractStringBuilder 的源码,源码里面没有秘密。

1
2
3
4
5
6
7
8
9
10
11
abstract class AbstractStringBuilder implements Appendable, CharSequence {
/**
* The value is used for character storage.
*/
char[] value;
/**
* The count is the number of characters used.
*/
int count;

}

这里重点看字符数组 value。跟 String 类最大的区别就是没有用 private final 关键字进行修饰,而且类内部有修改 value 字符数组的方法,比如setCharAt。这就说明继承自 AbstractStringBuilderStringBuilderStringBuffer 都是可变的。

从是否时可变对象这个角度来说,我们在声明字符串常量的时候应该考虑是String类。在需要用字符串类型作为Mapkey值的时候,应该考虑使用String变量。

既然都是可变的,我们再看看StringBuilderStringBuffer之间有什么区别。我们还是先看源码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public final class StringBuffer
extends AbstractStringBuilder
implements java.io.Serializable, CharSequence{

/**
* A cache of the last value returned by toString. Cleared
* whenever the StringBuffer is modified.
*/
private transient char[] toStringCache;

/** use serialVersionUID from JDK 1.0.2 for interoperability */
static final long serialVersionUID = 3388685877147921107L;

@Override
public synchronized StringBuffer append(String str) {
toStringCache = null;
super.append(str);
return this;
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
public final class StringBuilder
extends AbstractStringBuilder
implements java.io.Serializable, CharSequence{

/** use serialVersionUID for interoperability */
static final long serialVersionUID = 4383685877147921099L;

@Override
public StringBuilder append(String str) {
super.append(str);
return this;
}
}

这两个类里面的方法最主要的区别就是 append 方法有没有被关健字 synchronized 修饰。有一定基础的同学都知道synchronized关键字是跟线程安全相关的。
所以从源码中我们就可以看出这两个类最大的区别,StringBuilder是非线程安全的,性能较好,StringBuffer 是线程安全的,性能较StringBuilder差。
有人问为什么StringBuilder性能较好呢,因为不用加锁啊。

上面说了他们之间的异同点之后,我们基本上也就知道什么场景改用什么类了。
下面是我做的一个简单的总结。希望对你们有帮助。

类名 可变性 安全性 总结
String 不可变 线程安全 声明字符串常量。用作HashMap的键值。尽量不做字符串拼接操作。
StringBuilder 可变 非线程安全 频繁修改字符串值,单线程下使用。
StringBuffer 可变 线程安全 频繁修改字符串值,多线程下使用。

这篇文章与之前的两篇文章 Java里面的String对象到底神奇在什么地方为什么Java里面的String对象是不可变的 基本讲清了Java里面跟字符串相关的问题。

-------------本文结束-------------
坚持原创技术分享,您的支持将鼓励我继续创作!
0%