前言
Java中用于处理字符串常用的有三个类:java.lang.String、java.lang.StringBuffer、java.lang.StrungBuilder。三者共同之处:都是final类,不允许被继承,主要是从性能和安全性上考虑的,因为这几个类都是经常被使用着,且考虑到防止其中的参数被修改影响到其他的应用。
String类
先看一下JDK中String的部分源码:
public final class String
implements java.io.Serializable, Comparable<String>, CharSequence {
/** The value is used for character storage. */
private final char value[];
/** Cache the hash code for the string */
private int hash; // Default to 0
public String() {
this.value = "".value;
}
public String(String original) {
this.value = original.value;
this.hash = original.hash;
}
public String(char value[]) {
this.value = Arrays.copyOf(value, value.length);
}
...
可以看到String类和value都是final类型的,这样就表明String是无法被继承的,value是无法被改写的。当通过String的构造函数初始化新的String对象时,也只是根据传入的引用对象的value和hashcode进行了赋值。
StringBuilder和StringBuffer
先看一下它们在JDK中的部分源码:
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() {
}
AbstractStringBuilder(int capacity) {
value = new char[capacity];
}
...
}
public final class StringBuilder
extends AbstractStringBuilder
implements java.io.Serializable, CharSequence
{
public StringBuilder() {
super(16);
}
public StringBuilder(int capacity) {
super(capacity);
}
public StringBuilder(String str) {
super(str.length() + 16);
append(str);
}
@Override
public StringBuilder append(String str) {
super.append(str);
return this;
}
...
}
public final class StringBuffer
extends AbstractStringBuilder
implements java.io.Serializable, CharSequence
{
private transient char[] toStringCache;
public StringBuffer() {
super(16);
}
public StringBuffer(int capacity) {
super(capacity);
}
public StringBuffer(String str) {
super(str.length() + 16);
append(str);
}
@Override
public synchronized StringBuffer append(String str) {
toStringCache = null;
super.append(str);
return this;
}
...
}
可以看到StringBuffer和StringBuilder一样,都是用了char数组保存value,append也是调用了AbstractStringBuilder的append方法。区别在于StringBuffer中的方法上加了synchronized关键字。
三者的区别
1、执行速度
StringBuilder > StringBuffer > String
我们知道String是字符串常量,不可变对象,因此每次对String进行操作的时候实际上是生成了一个新的String对象,然后将指针指向新的String对象上,之前的String对象就没有了指针引用,当内存中无引用的对象多了之后,就会触发JVM的GC操作了。
StringBuilder和StringBuffer是字符串变量,因此当我们对字符串做操作的时候,实际上都是操作的同一个对象,不会创建新的对象。
注意:
String str="hel"+"lo";
String a = "hel";
String b ="lo";
String c = a+b;
上面的两部分代码虽然输出的结果都是“hello”,但是在jvm中的内存分布是完全不同的。
String str="hel"+"lo"; 中的str是一个编译时常量,最后分配到内存里面的只有"hello" 这一款内存区域。
而下面的三行代码,则需要在内存中分配三块地址,【"hel","lo","hello"】。
2、线程安全
StringBuilder是线程不安全的,而StringBuffer是线程安全的。
java.lang.StringBuilder一个可变的字符序列是5.0新增的。此类提供一个与 StringBuffer 兼容的 API,但不保证同步。该类被设计用作 StringBuffer 的一个简易替换,用在字符串缓冲区被单个线程使用的时候(这种情况很普遍)。如果可能,建议优先采用该类,因为在大多数实现中,它比 StringBuffer 要快。两者的方法基本相同。所以如果要进行的操作是多线程的,那么就要使用StringBuffer,但是在单线程的情况下,还是建议使用速度比较快的StringBuilder。
结语
String:适用于少量的字符串操作的情况
StringBuilder:适用于单线程下在字符缓冲区进行大量操作的情况
StringBuffer:适用多线程下在字符缓冲区进行大量操作的情况
网友评论