String,StringBuffer和StringBuilder的区别是面试中高频出现的问题,很多有开发经验的程序员,如果不注意,也不知道其中的一些区别,今天我们就来谈谈这三者的区别。

一 Java String 类

字符串,我们经常会用到,Java中字符串属于对象,Java提供了String类来创建和操作字符串。底层是char型数组。

但是特别关注的是字符串是不可变的,这就导致我们每次对String的操作都会重新创建String对象,这样不仅效率低下,而且频繁创建导致内存的浪费。




java中char和byte的区别 java中char和string的区别_java中char和byte的区别


我们可以看到,初始化str为“hello”,此时需要分配一次地址给str,在str后面加上字符串“world”,此时为“world”开辟内存空间。最终的“hello world”还要分配一次内存空间。这样简单的一个字符串相加,需要分配三次内存,不得不说是对内存的极大浪费。

为了解决这个问题,我们就需要Java 为我们提供的两个类StringBuffer和StringBulder.

二 StringBuffer和StringBulder

和 String 类不同的是,StringBuffer 和 StringBuilder 类的对象能够被多次的修改,并且不产生新的未使用对象。

我们可以先看一下两者的继承关系:


java中char和byte的区别 java中char和string的区别_Java_02


java中char和byte的区别 java中char和string的区别_字符串_03


我们可以看到StringBuffer和StringBuilder所继承和实现的类都是相同的。查看源码可以看到,两者提供的方法也基本相同。

StringBuffer在方法前添加了synchronized关键字来实现线程安全,而StringBuilder是线程不安全的。

这三者的底层都是使用char[]存储,如


String str = new String() //底层会是  new char[];
String str = new String("abc") // 底层会 用new char[]{'a','b','c'};存储


但是对于StringBuffer, StringBuffer sb = new StringBuffer()我们查看底层源码:


/**
     * Constructs a string buffer with no characters in it and an
     * initial capacity of 16 characters.
     */
    public StringBuffer() {
        super(16);
    }
//调用父类的构造方法,创建一个长度为16的 char[16]。


StringBuffer和StringBuilder长度是可变的,这一点我们可以通过AbstractStringBuilder的newCapacity方法可以看出:


/**
     * Returns a capacity at least as large as the given minimum capacity.
     * Returns the current capacity increased by the same amount + 2 if
     * that suffices.
     * Will not return a capacity greater than {@code MAX_ARRAY_SIZE}
     * unless the given minimum capacity is greater than that.
     *
     * @param  minCapacity the desired minimum capacity
     * @throws OutOfMemoryError if minCapacity is less than zero or
     *         greater than Integer.MAX_VALUE
     */
    private int newCapacity(int minCapacity) {
        // overflow-conscious code
        int newCapacity = (value.length << 1) + 2;
        if (newCapacity - minCapacity < 0) {
            newCapacity = minCapacity;
        }
        return (newCapacity <= 0 || MAX_ARRAY_SIZE - newCapacity < 0)
            ? hugeCapacity(minCapacity)
            : newCapacity;
    }


三 总结

  1. String的值是不可变的,这就导致每次对String的操作都会生成新的String对象,不仅效率低下,而且浪费大量优先的内存空间
  2. StringBuffer是可变类,和线程安全的字符串操作类,任何对它指向的字符串的操作都不会产生新的对象。每个StringBuffer对象都有一定的缓冲区容量,当字符串大小没有超过容量时,不会分配新的容量,当字符串大小超过容量时,会自动增加容量
  3. StringBuilder可变类,速度更快,线程不安全,单线程使用