【源码学习】String、StringBuilder、StringBuffer他们之间有什么不一样?

一、如何初始化一个String对象?

相信有些小伙伴会通过这几种方式进行创建。

String str = "陈大嘴"

String str = new String("陈大嘴");

那还有没有其他创建方式呢?我们来看以下创建方式。

String str = new String(new char[]{'陈', '大','嘴'});

String str = new String(new byte[]{-23, -103, -120, -27, -92, -89, -27, -104, -76});
....

二、StringBuilder、StringBuffer和String哪个速度更快一点呢?

首先我们进行一个测试,以十万数据为例:

String

        long startTime = System.currentTimeMillis();
        String str = "";
        for (int i = 0; i < 100000; i++) {
            str += i;
        }
        System.out.println("String 耗时:" + (System.currentTimeMillis() - startTime) + "毫秒");

StringBuilder

long startTime = System.currentTimeMillis();
StringBuilder str = new StringBuilder();
for (int i = 0; i < 1000000; i++) {
    str.append(i);
}
System.out.println("StringBuilder 耗时" + (System.currentTimeMillis() - startTime) + "毫秒");

StringBuffer

StringBuffer str = new StringBuffer();
for (int i = 0; i < 1000000; i++) {
    str.append(i);
}

经过测试结果如下:
在这里插入图片描述

  • 可见String在数据量大的情况下进行字符串拼接时候效率是非常低的
  • StringBuilder、StringBuffer,因为没有发生多线程竞争也就没有锁升级,所以两个类耗时几乎相同,当然在单线程下更推荐使用 StringBuilder

三、为什么StringBuilder比String快这么多?

  1. String在java中是不可变长的,一旦初始化就不能修改长度,简单的字符串拼接其实是创建新的String对象,再把拼接后的内容赋值给新的对象,在频繁修改的情况下会频繁创建对象,而StringBuilder则不会,从头到尾只有一个实例对象
  2. 实际上代码类似如下:
String str = "";
for (int i = 0; i < 10000; i++) {
    str = new StringBuilder().append(str).append(i).toString();
}
 

String 在进行字符串拼接时候会不停的去new一个对象,然后再进行append拼接操作,而StringBudder相当于把他提出来了,不需要频繁的创建对象。

String源码解析:
String 部分源码

  • 不可变(final) ,字符串创建后是不可变的,你看到的+加号连接操作,都是创建了新的对象把数据存放过去,通过源码就可以看到;
  • 数组, char value[];
  • intern
    看以下几个示例:
String str_1 = new String("ab");
String str_2 = new String("ab");
String str_3 = "ab";

System.out.println(str_1 == str_2);
System.out.println(str_1 == str_2.intern());
System.out.println(str_1.intern() == str_2.intern());
System.out.println(str_1 == str_3);
System.out.println(str_1.intern() == str_3);

输出结果是如下:

false
false
true
false
true

可以看以下图解:
在这里插入图片描述

  1. 先说 ==,基础类型比对的是值,引用类型比对的是地址。另外,equal 比对的是哈希值。
  2. 两个new出来的对象,地址肯定不同,所以是false。
  3. new出来的两个对象通过intern 将数据存放到常量池,然后进行比较,比较的是常量池的值,不是堆中的地址。所以是true
  4. str_1.intern() == str_3 比较的是常量池的值,所以true

StringBuilder 源码

1. 初始化

初始化的时候可以
new StringBuilder();
new StringBuilder(16);
new StringBuilder("abc");
可以默认,也可以指定初始化容量,还可以初始化数据。

2. 添加元素
stringbuilder.append(“x”);

3. 扩容
源码

/**
 * This method has the same contract as ensureCapacity, but is
 * never synchronized.
 */
private void ensureCapacityInternal(int minimumCapacity) {
    // overflow-conscious code
    if (minimumCapacity - value.length > 0)
        expandCapacity(minimumCapacity);
}

/**
 * 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,就跟操作数组的原理一样,都需要检测容量大小,按需扩容。扩容的容量是 n * 2 + 2,另外把原有元素拷贝到新新数组中

StringBuffer源码

@Override
public synchronized StringBuffer append(String str) {
    toStringCache = null;
    super.append(str);
    return this;
}

基本上底层API和Stringbuilder一致,只不过他加了synchronized 锁,因此StringBuffer是线程安全的。

常见Api:
1 str.concat(“cde”) 字符串连接,替换+号
2 str.length() 获取长度
3 isEmpty() 判空
4 str.charAt(0) 获取指定位置元素
5 str.codePointAt(0) 获取指定位置元素,并返回ascii码值
6 str.getBytes() 获取byte[]
7 str.equals(“abc”) 比较
8 str.equalsIgnoreCase(“AbC”) 忽略大小写,比对
9 str.startsWith(“a”) 开始位置值判断
10 str.endsWith(“c”) 结尾位置值判断
11 str.indexOf(“b”) 判断元素位置,开始位置
12 str.lastIndexOf(“b”) 判断元素位置,结尾位置
13 str.substring(0, 1) 截取
14 str.split(“,”) 拆分,可以支持正则
15 str.replace(“a”,“d”)、replaceAll 替换
16 str.toUpperCase() 转大写
17 str.toLowerCase() 转小写
18 str.toCharArray() 转数组
19 String.format(str, “”) 格式化,%s、%c、%b、%d、%x、%o、%f、%a、%e、%g、%h、%%、%n、%tx
20 str.valueOf(“123”) 转字符串
21 trim() 格式化,首尾去空格
22 str.hashCode() 获取哈希值

  • 4
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值