String、StringBuffer和StringBuilder

在java中String、StringBuffer和StringBuilder都可以对字符串进行操作,但各自具有不同的应用场景。

(1)String和StringBuffer

String是不可变类,也就是说String一旦被创建,其值就不能够被修改,因此其在那些不需要修改的共享变量中比较适合;StringBuffer则是可以改变的。

String初始化方式有两种方式,分别是赋值(String s = "Hello")和构造函数(String s = new String("Hello"));StringBuffer则只有构造函数这一种方式。

当需要对String进行修改时,会先将创建一个StringBuffer对象,然后调用StringBuffer的append方法,最后调用toString方法返回修改后的字符串。

由于这种情况导致String进行修改时需要花费更多的时间和资源,我们给出测试代码及结果(包括三种类型):

package com.bjtu.StringTest;

/**
 * created by LMR on 2019/5/27
 */
public class StringAndStringBuffer {

    public static void main(String[] args) {

        testString();
        testStringBuffer();
        testStringBuilder();

    }

    public static void testString(){

        String s = "Hello";
        String s2 = "world";
        long start = System.currentTimeMillis();
        for (int i = 0; i < 30000; i++)
            s += s2;
        long time = System.currentTimeMillis() - start;
        System.out.println("testString: " + time);
    }

    public static void testStringBuffer(){

        StringBuffer buffer = new StringBuffer("Hello");
        String s2 = "world";
        long start = System.currentTimeMillis();
        for (int i = 0; i < 30000; i++)
            buffer.append(s2);
        long time = System.currentTimeMillis() - start;
        System.out.println("testStringBuffer: " + time);
    }

    public static void testStringBuilder(){

        StringBuilder builder = new StringBuilder("Hello");
        String s2 = "world";
        long start = System.currentTimeMillis();
        for (int i = 0; i < 30000; i++)
            builder.append(s2);
        long time = System.currentTimeMillis() - start;
        System.out.println("testStringBuilder: " + time);
    }
}

结果:

testString: 20581
testStringBuffer: 4
testStringBuilder: 2

从结果上可以看出StringBuffer和StringBuilder在修改字符串时,要远优于String。

(2)StringBuffer和StringBuilder

首先介绍两者的相同点,两个方法都是可以动态修改字符串,查看其源码可以发现,两种方法底层都是使用char数组来存储字符串:

 /**
     * The value is used for character storage.
     */
    char[] value;

这种方式与ArrayList存储数据类似,在修改数据时需要动态扩充数组,其方式也基本相同,详情可以查看我的博客https://blog.csdn.net/qq_16669583/article/details/90489190

两者的不同点在于StringBuffer是线程安全的,而StringBuilder是线程不安全的,这是由于在底层实现中,StringBuffer对字符数组的操作添加了同步锁:

 @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;
    }

而StringBuilder则没有:

  @Override
    public StringBuilder append(Object obj) {
        return append(String.valueOf(obj));
    }

    @Override
    public StringBuilder append(String str) {
        super.append(str);
        return this;
    }

因此在单线程程序中优先使用StringBuilder,而多线程中使用StringBuffer,这也是在前面例子中为什么StringBuilder操作时间低于StringBuffer的原因。

你可能感兴趣的:(JAVA)