Java基础08 String、StringBuilder、StringBuffer的区别

String 类

  在Java的编程中,字符串是运用的比较多的类型,字符串是由Java的String类来创建的,需要注意的是String类被 final 修饰的类,这意味着该类不能继承,该类的对象值是不可变的。

public final class String
    implements java.io.Serializable, Comparable<String>, CharSequence {

  但在平时使用的时候,我们经常这样操作来改变String对象变量的值

String str = "hello";
str += "world"; 

  其实这样的操作很消耗内存,浪费存储空间,我们来看下上面的语句块会产生哪些操作。
String

  1. 在堆上开辟一个空间用于存储 hello
  2. 在栈上分配一个空间用于存储str,存储的值是堆内存的 hello 地址
  3. 在堆上开辟一个空间用于存储 world.
  4. 拼接 hello 与 world.两个字符串,放入堆另外开辟的一个内存空间
  5. 栈上存储str的值变为 helloworld. 的堆内存地址

  经过上面的步骤分析,我们可以知道,String 类型的字符串在进行拼接的时候,在堆内存上开辟了三次空间,而且只使用其中一个内存空间,这无疑是对堆内存空间的极大的浪费。

  为了能解决这个问题,也就引入了 StringBuild 和 StringBuffer。

StringBuffer与StringBuilder

  StringBuilder 与 StringBuffer 两个类主要用于对字符串频繁修改的场景,它们是对 String 的优化,在追加字符串的时候不会去堆上开辟新的空间,会直接在已有的堆空间追加。
String相关结构层次

  上图是String、StringBuffer、StringBuilder的层级关系图,我们可以看出StringBuilder与StringBuffer继承了AbstractStringBuilder抽象类,查看源码可知,StringBuilder与StringBuffer最终使用的方法还是它们的父类AbstractStringBuilder中的方法,唯一不同的是StringBuffer比StringBuilder多做了一个加锁的操作,这也就导致StringBuffer是线程安全的,但执行效率比较低,而StringBuilder不是线程安全的,但执行效率较高。

StringBuilder

public StringBuilder(String str) {
    super(str.length() + 16);
    append(str);	// 调用本类的
}

@Override
public StringBuilder append(String str) {	// 没有加锁
    super.append(str);	// 直接调用父类的追加方法
    return this;
}

public AbstractStringBuilder append(String str) {
    if (str == null)
        return appendNull();
    int len = str.length();
    ensureCapacityInternal(count + len);
    str.getChars(0, len, value, count);
    count += len;
    return this;
}

StringBuffer

public StringBuffer(String str) {
    super(str.length() + 16);
    append(str);	// 调用本类的
}

@Override
public synchronized StringBuffer append(String str) {	// 加锁
    toStringCache = null;
    super.append(str);	// 调用父类的追加方法
    return this;
}

public AbstractStringBuilder append(String str) {
    if (str == null)
        return appendNull();
    int len = str.length();
    ensureCapacityInternal(count + len);
    str.getChars(0, len, value, count);
    count += len;
    return this;
}

  可能有些疑问,为什么String、StringBuilder、StringBuffer三个类都是被 final 修饰,但只有String的值是不可变的呢?
  其实很简单,StringBuilder、StringBuffer确实是被 final 修饰的,而且他们本身也确实是不可变的,但我们需要注意的一点,他们追加的真正操作是在它们的父类中进行的,而它们的父类是没有被 final 修饰,这也就间接的理解StringBuilder、StringBuffer是可变的字符串,追加的时候不需要在堆内存开辟新的空间。

public final class StringBuilder
    extends AbstractStringBuilder
    implements java.io.Serializable, CharSequence
{

总结:三者的区别

  1. 三者都是被 final 修饰的类,但String类是不可变的,而其它两个可以间接理解为可变的。
  2. StringBuilder和String不是线程安全的,StringBuffer是线程安全的。
  3. 效率:StringBuilder > StringBuffer。
  4. 在字符串变量的值不经常改变的情况下(甚至不变),可以使用String,也可以使用StringBuilder;在字符串变量的值经常改变且不是多线程环境下,使用StringBuilder;在字符串变量的值经常改变且在多线程环境下,使用StringBuffer.
原文地址:https://www.cnblogs.com/sophia-show/p/13646885.html