String StringBuilder and StringBuffer

这里主要关注String,StringBuilder和StringBuffer的在创建String时候的区别

执行原理

String

在创建一个字符串的时候如果这样使用:

 String s = "s";
 System.out.println(s.hashCode());
 s = s + "s1";
 System.out.println(s.hashCode());

运行结果:

 115
114129

从运行结果可以很明显的看到s的hashcode已经变了,(hashcode是根据一定的规则将与对象相关的信息,比如对象的存储地址,对象的字段等,映射成一个数值,这个数值称作为散列值)。基本上可以确定 +”s1”后的s已经不是原来的s了。

JVM是这样解析这段代码的:首先创建对象s,赋予一个abcd,然后再创建一个新的对象s用来执行第二行代码,也就是说我们之前对象s并没有变化,所以我们说String类型是不可改变的对象了,由于这种机制,每当用String操作字符串时,实际上是在不断的创建新的对象,而原来的对象就会变为垃圾被GC回收掉。

StringBuilder append

StringBuilder这样使用:

  StringBuilder stringBuilder = new StringBuilder(20);
  stringBuilder.append("c");
  System.out.println(stringBuilder.hashCode());
  stringBuilder.append('d');
  System.out.println(stringBuilder.hashCode());

运行结果:

2055281021
2055281021

StringBuilder的append实现:

  1. 如果参数是char : stringBuilder.append(‘d’)
    内部实现:
public AbstractStringBuilder append(char c) {
    ensureCapacityInternal(count + 1);
    value[count++] = c;
    return this;
}

可以看到是直接改变数组中第count+1位置的值
2. 如果参数是String: stringBuilder.append(“c”)
内部实现:
最终会调用String的getchars方法:

//srcBegin 源字符串起始位置
//srcEnd源字符串结束位置
//dst[] 目的字符数组
//dstBegin目的字符数组的起始位置
 public void getChars(int srcBegin, int srcEnd, char dst[], int dstBegin) {
        if (srcBegin < 0) {
            throw new StringIndexOutOfBoundsException(srcBegin);
        }
        if (srcEnd > value.length) {
            throw new StringIndexOutOfBoundsException(srcEnd);
        }
        if (srcBegin > srcEnd) {
            throw new StringIndexOutOfBoundsException(srcEnd - srcBegin);
        }
        System.arraycopy(value, srcBegin, dst, dstBegin, srcEnd - srcBegin);
    }

执行的时候使用System.arraycopy方法,将源字符串(即参数), 拷贝到目的字符数组,以dstBegin为开始,拷贝srcEnd - srcBegin个。

StringBuffer append

StringBuffer的append实现:

  • 如果参数是char,stringBuffer.append(‘b’);
    同StringBuilder
  • 如果参数是String, stringBuffer.append(“a”);
    同StringBuilder

StringBuilder和StringBuffer的区别

从上面的描述中可以看到StringBuilder和StringBuffer在构建字符串的时候原理是一样的。从源码来看StringBuilder和StringBuffer有这样的几点区别:

  • StirngBuffer中使用了private transient char[] toStringCache;来缓存最近一次执行toString()方法时的数组。只要StringBuffer有任何变更都会将toStringCache清空
    代码:
@Override
public synchronized String toString() {
    if (toStringCache == null) {
        toStringCache = Arrays.copyOfRange(value, 0, count);
    }
    return new String(toStringCache, true);
 }
 @Override
    public synchronized StringBuffer append(char c) {
        toStringCache = null;
        super.append(c);
        return this;
    }
  • StringBuffer中的每个方法都是synchronized的,从而保证了多线程环境下的线程安全性。也是因此在执行速度上StringBuilder是大于StringBuffer的
    -综上可以看出在执行效率上StringBuilder>StringBuffer>String

StringBuilder和StringBuffer的相同点

(1)StringBuffer继承自AbstractStringBuilder,底层实现是一个char[] value, 默认的capacity是16,可以通过构造函数改变数组的默认capacity,如上面代码的第一行。

(2)StringBuilder和StringBuffer的扩容机制首先是把容量变为原来容量的2倍加2。最大容量是Integer.MAX_VALUE,也就是0x7fffffff。
(3)StringBuilder和StringBuffer的默认容量都是16,最好预先估计好字符串的大小避免扩容带来的时间消耗。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值