String、StringBuilder和StringBuffer在使用上有什么区别?

从相同点来看,这三者都可以用来表示字符串;从不同点看,它们在可变性、线程安全和性能上有着很不同的特性。

一、相同点

它们都可以用来表示字符串:

    public static void main(String[] args){
        String name1 = "zhangsan";

        String name2 = new String("zhangsan");

        StringBuilder sb1 = new StringBuilder("zhangsan");

        StringBuffer sb2 = new StringBuffer("zhangsan");
    }

二、不同点

2.1 可变性

2.1.1 String的不可变性

String一旦用来表示一个字符串,那么这个字符串所对应的地址中的内容就是不可更改的。

    public static void main(String[] args){
        String name1 = "zhangsan";
    }

如上代码中,name1只是一个引用地址,这个地址中的内容是“zhangsan”,而该内容是不允许被更改。这个可以通过阅读String的源码得以确认,如下代码中value[]被声明为final类型,即不可更改。

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

我们使用如下代码更改的只是引用地址,使得引用指向一个新的字符串地址,而原来的字符串地址中的内容还是保持原样。

    public static void main(String[] args){
        String name1 = "zhangsan";

        String name2 = "lisi";

        name1 = name2;
    }

2.1.2 StringBuilder和StringBuffer的可变性

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

阅读源码,发现StringBuilder和StringBuffer都是继承AbstractStringBuilder,而AbstractStringBuilder中的value并没有声明为final类型,因此其值是允许被改变的。

abstract class AbstractStringBuilder implements Appendable, CharSequence {
    /**
     * The value is used for character storage.
     */
    char[] value;

2.2 线程安全

2.2.1 String是线程安全的

String所指向的值是不可改变的,因此天然是线程安全的。

2.2.2 StringBuilder不是线程安全的

我们可以做个试验来验证。

// 待补充

2.2.3 StringBuffer是线程安全的

将如上的代码中sb1替换为StringBuffer类型进行相同的测试,不管执行多少次,得出的结果都是确定的。

StringBuilder和StringBuffer为什么会有这样的区别呢?我们可以看看相同方法在各自源代码中的区别:

    // AbstractStringBuilder源码,StringBuilder由此继承
    @Override
    public int length() {
        return count;
     }
    // StringBuffer源码,重写了AbstractStringBuilder中的相同方法
    @Override
    public synchronized int length() {
        return count;
    }

可以看出,StringBuffer对方法进行了重写,增加了synchronized关键字,对方法进行同步控制,从而实现线程安全。

2.3 性能

String因为不可改变其值,当给它赋予新的字符串时,实际是让其指向一个新的字符串地址,因此相对于StringBuilder和StringBuffer而言,空间和性能都有浪费。

StringBuffer相对于StringBuilder而言,增加了线程安全的控制,因此在性能上也会不如StringBuilder。

三、使用总结

  • 操作少量的字符串数据的时候,可以考虑String;
  • 单线程场景下操作大量字符串数据的时候,考虑使用StringBuilder;
  • 多线程场景下操作大量字符串数据的时候,考虑使用StringBuffer;

你可能感兴趣的:(String、StringBuilder和StringBuffer在使用上有什么区别?)