关于Java中的String StringBuffer StringBuilder的理解。

String StringBuffer StringBuilder的区别是什么?

  • 可变性

    String类是不可变类,即一旦String对象创建之后,对象中包含的字符串就不能再进行任何的修改,若要更改String变量引用的字符串,那么只能放弃对原先字符串的引用,改为引用新的字符串。

public class StringDemo{
	public static void main(String[] args){
        String str = "String";
        System.out.println("更改前:"+str);
        str+=" Test";
        System.out.println("更改后:"+str);
    }
    
}

输出结果如下:

更改前:String
更改后:String Test

从控制台的输出结果可以看出str字符串是改变了的,但是改变的不是字符串,而是str变量引用的改变,原来堆内存中保存的“String”字符串还是没有改变,因为String类中使用final关键字修饰数组来保存字符串,下面是字符串类的Java源码。

public final class String
    implements java.io.Serializable, Comparable, CharSequence {
    /** The value is used for character storage. */
    private final char value[]; // Java9之前
    private final byte[] value;  // Java9之后

下面结合下图进行说明。
关于Java中的String StringBuffer StringBuilder的理解。_第1张图片

在执行str+=“ Test”时,除了Java环境产生“String”和“String Test”字符串常量以外,还存在一个“Test”字符串常量。因为String类是不可变的,所以会产生很多临时变量,会增加内存消耗,而使用StringBuffer或者StringBuilder就可以很好的解决这个问题。StringBuffer和StringBuilder都继承自AbstractStringBuilder,AbstractStringBuilder是使用字符数组char[] value ,但是没有用final关键字修饰,所以这两种对象都是可变的。

  • 线程安全性

    String中的对象是不可变的,也就可以理解为常量,线程安全。AbstractStringBuilder是StringBuilder与StringBuffer的公共父类,定义了一些字符串的基本操作,如expandCapacity、append、insert、indexOf等公共方法。StringBuffer对方法加了同步锁或者对调用的方法加了同步锁,所以是线程安全的。

    StringBuffer.class部分源码

    public final class StringBuffer
        extends AbstractStringBuilder
        implements java.io.Serializable, CharSequence
    {
        @Override
        public synchronized int length() {
            return count;
        }
        @Override
        public synchronized int capacity() {
            return value.length;
        }
        @Override
        public synchronized void setLength(int newLength) {
            toStringCache = null;
            super.setLength(newLength);
        }
        @Override
        public synchronized StringBuffer append(Object obj) {
            toStringCache = null;
            super.append(String.valueOf(obj));
            return this;
        }
        @Override
        public synchronized StringBuffer append(String str) {
            toStringCache = null;
            super.append(str);
            return this;
        }
        @Override
        public synchronized StringBuffer delete(int start, int end) {
            toStringCache = null;
            super.delete(start, end);
            return this;
        }
        @Override
        public synchronized StringBuffer insert(int offset, String str) {
            toStringCache = null;
            super.insert(offset, str);
            return this;
        }
    }
    
    

    而StringBuilder并没有对方法进行加同步锁,所以是非线程安全的。

  • 性能

    每次对String类型进行改变的时候,都会生成一个新的String对象,然后将指针指向新的String对象。StringBuffer每次都会对StringBuffer对象本身进行操作,而不是生成新的对象并改变对象引用。相同情况下使用StringBuilder相比使用StringBuffer仅能获得10%~15%左右的性能提升,但却要冒多线程不安全的风险。

总结

  1. 操作少量的数据:适用String
  2. 单线程操作字符串缓冲区下操作大量数据:使用StringBuilder
  3. 多线程操作字符串缓冲区下操作大量数据:使用StringBuffer

你可能感兴趣的:(java,字符串)