深入理解String、StringBuilder、StringBuffer

字符串相关类

String类

String是一个典型的数组应用
结合源码来看:

    private final char value[];
    private int hash; // Default to 0

在String类中声明了一个私有的常量数组,因此声明后的值外部无法直接操作,但是:

public String() {
        this.value = new char[0];
}
public String(String original) {
        this.value = original.value;
        this.hash = original.hash;
}

通过String提供的构造方法可以操作该值,并且只能被定义一次
这段代码表示在String类中对象创建后无法修改,重新赋值表示重新创建了一个新的对象;

equals和==

equals比较内容是否相等,==比较引用地址是否相等;
但是有一点需要注意,对象只有初始化才会在堆中创建该对象的属性;如果:

String a = "aaa";
String b = "aaa";
System.out.print(a==b);

最后结果为true,这是因为,a和b并未创建新的对象,而是直接将指针指向了常量池里已经加载过的“aaa”这个值

new关键字
String a = new String("abc");
String b = "abcd";

这两种写法是有明显区别的;
a的value会被加载到堆中,value的指针指向常量池中的“abc”;
b是指针直接指向常量池中的"abcd";
因此可以说new一个String对象实际该对象创建了两次;

StringBuilder类

新建一个StringBuilder对象,跳转进去查看它的源码可以发现,它的默认长度为16

public StringBuilder() {
        super(16);
}
AbstractStringBuilder(int capacity) {
        value = new char[capacity];
}
传入int类型代表长度:
public StringBuilder(int capacity) {
        super(capacity);
}
传入String类型代表:
 public StringBuilder(String str) {
        super(str.length() + 16);
        append(str);
}

返回一个字符串长度+16的char类型数组并追加String字符串

StringBuilder自动扩容

在使用StringBuilder中的append方法追加字符串时,如果我们在初始化时未指定长度,那它的默认长度为16,如果我们追加的字符超过该长度,StringBuilder会调用一个自动扩容的方法,如下:

/**
     * This implements the expansion semantics of ensureCapacity with no
     * size check or synchronization.
     */
    void expandCapacity(int minimumCapacity) {
        int newCapacity = value.length * 2 + 2;
        if (newCapacity - minimumCapacity < 0)
            newCapacity = minimumCapacity;
        if (newCapacity < 0) {
            if (minimumCapacity < 0) // overflow
                throw new OutOfMemoryError();
            newCapacity = Integer.MAX_VALUE;
        }
        value = Arrays.copyOf(value, newCapacity);
    }

这一段是StringBuilder源码当中对于使用append方法扩容的方法,当追加的字符长度超过当前定义StringBuilder的长度时,新建一个原数组长度2倍+2的一个新数组(如果新建的还是不够,继续新建,就数组无指针引用,将会被回收),最后替换数组,返回新数组

StringBuffer

和StringBuilder基本一致;
StringBuilder线程不安全,效率高
StringBuffer线程安全,效率低

因为StringBuffer中所有的方法都添加了synchronized关键字来表示同步,因此StringBuffer是线程安全的,但是因为是多线程,要一个方法关闭后,另一个方法才能被调用,因此,它的效率比较低;
一般声明在方法块中的局部变量大多都不会考虑线程安全,因此,从效率触发,我们选择较多的还是StringBuilder

String和StringBuilder的区别

我们首先来分析String和StringBuilder源码中是怎样定义它们的值
String:(摘取片段)

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

    /** Cache the hash code for the string */
    private int hash; // Default to 0

StringBuilder:(摘取片段)

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

    /**
     * The count is the number of characters used.
     */
    int count;

从它们的定义我们可以看出String定义的值是private final char value[],一个私有的常量数组,因此它的值是不可更改的;
而StringBuilder (继承至AbstractStringBuilder )声明的是一个default char[] value ;同一个包下的其他类可对它进行操作;
因此我们可以得出:
String是不可变字符序列,而StringBuilder是可变字符序列;又因为String对象不可变,变则相当于重新创建对象,因此从运行效率来说,StringBuilder是远远大于String的,因此它们的关系可表示为StringBuilder>StringBuffer>String

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值