三者源码上的区别:
- 在java 8 ,也就是jdk1.8中我们可以看到关于String的部分源码
public final class String
implements java.io.Serializable, Comparable<String>, CharSequence {
/** The value is used for character storage. */
private final char value[];
}
在源码中我们可以看见用来储存字符串的字符数组被定义成了final常量。
private final char value[];
所以说String是不可变字符串。
- 在jdk1.8中关于StringBuilder的部分源码
public final class StringBuilder
extends AbstractStringBuilder
implements java.io.Serializable, CharSequence
{
/** use serialVersionUID for interoperability */
static final long serialVersionUID = 4383685877147921099L;
/**
* Constructs a string builder with no characters in it and an
* initial capacity of 16 characters.
*/
public StringBuilder() {
super(16);
}
}
- jdk1.8中StringBuffer的部分源码
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;
/**
* Constructs a string buffer with no characters in it and an
* initial capacity of 16 characters.
*/
public StringBuffer() {
super(16);
}
}
4.StringBuilder和StringBuffer都继承AbstractStringBuilder,以下是AbstractStringBuilder的部分源码
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;
在AbstractStringBuilder的源码中发现,用来存储字符串的字符数组并没有被定义成final常量。
根据char[] value;
这行代码,StringBuilder和StringBuffer都是可变字符串。
三者关于线程是否安全的问题:
线程,我们简单理解为每个程序执行的基本单元。
String字符串是常量,它是不可被改变的,所以String线程是安全的。
private final char value[];
AbstractStringBuilder是StringBuilder与StringBuffer的公共父类,定义了一些字符串的基本操作,如expandCapacity(),append(),insert(),indexOf()等公共方法。
StringBuffer对方法加了同步锁(synchronized)或者对调用的方法加了同步锁(synchronized),所以是线程安全的。
@Override
public synchronized String substring(int start, int end) {
return super.substring(start, end);
}
/**
* @throws StringIndexOutOfBoundsException {@inheritDoc}
* @since 1.2
*/
@Override
public synchronized StringBuffer insert(int index, char[] str, int offset,
int len)
{
toStringCache = null;
super.insert(index, str, offset, len);
return this;
}
public int indexOf(String str) {
return indexOf(str, 0); //存在 public synchronized int indexOf(String str, int fromIndex) 方法
}
而在StringBuilder的源码中并没有加同步锁,所以StringBuilder是非线程安全的。
三者的运算速度问题:
StringBuilder > StringBuffer > String
StringBuilder 最快,StringBuffer 第二,String 最慢。
因为String是字符串常量,看如下代码:
String str="abc";
System.out.println(str);
str=str+"de";
System.out.println(str);
我们肉眼来看好像确实str被更改了,但是并不是这样的。
首先创建一个String对象str,并把“abc”赋值给str,然后在第三行中,其实又创建了一个新的对象也名为str,然后再把原来的str的值和“de”加起来再赋值给新的str,而原来的str就会被垃圾回收机制(GC)给回收掉了,所以,str实际上并没有被更改,也就是前面说的String对象一旦创建之后就不可更改了。
所以String字符串更改就是重新创建对象,重新赋值,重新创建对象,重新赋值……这样的循环
但是StringBuffer和StringBuilder都是可以更改的。
public static void testStringBuffer(){
long start = System.currentTimeMillis();
StringBuffer stringBuffer = new StringBuffer();
for(int i = 0;i<200000;i++){
stringBuffer.append(i);
}
System.out.println(System.currentTimeMillis() - start);
}
public static void testStringBuilder(){
long start = System.currentTimeMillis();
StringBuilder stringBuilder = new StringBuilder();
for(int i = 0;i<200000;i++){
stringBuilder.append(i);
}
System.out.println(System.currentTimeMillis() - start);
}
public static void main(String[] args) {
// TODO Auto-generated method stub
testStringBuffer();
testStringBuilder();
}
运行结果如下:
总结:
String:适用于少量的字符串操作的情况
StringBuilder:适用于单线程下在字符缓冲区进行大量操作的情况
StringBuffer:适用多线程下在字符缓冲区进行大量操作的情况