JVM对String拼接的优化

前言

今天在刷leetcode的时候,发现直接使用String进行拼接与StringBuilder进行拼接的效率差得很多,于是摸索了一下他们底层实现的区别。



StringBuilder

构造函数

class StringBuilder extends AbstractStringBuilder

    /**
     * Constructs a string builder with no characters in it and an
     * initial capacity of 16 characters.
     */
    public StringBuilder() {
        super(16);
    }
class AbstractStringBuilder

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

    AbstractStringBuilder(int capacity) {
        value = new char[capacity];
    }

在调用无参构造方法的时候,StringBuilder默认会创建一个长度为16的字符数组。


append方法

    public AbstractStringBuilder append(String str) {
    	// 为空判断
        if (str == null)
            return appendNull();
        int len = str.length();.
        // 判断是否需要扩容
        ensureCapacityInternal(count + len);
        // 加入到value数组中
        str.getChars(0, len, value, count);
        // 长度指针
        count += len;
        return this;
    }

append方法会把每次加入的字符串暂存到value字符数组中。(如果传入的字符串为null,则存入字符串"null")当调用toString()方法时,就会把字符数组转换成一个String对象输出。



String

String的拼接分为两种情况

  1. 常量拼接
  2. 变量拼接

常量拼接

String str = "a" + "b" + "c";

以上这种情况被称为常量拼接,也就是每一个值都是确定好的,jvm在编译期就会直接完成拼接。


变量拼接

String a = "a";
String b = "b";
String c = "c";
String str = a + b + c + "d";

以上这种情况被称为变量拼接,只要在拼接过程中有一个变量,那么就属于变量拼接。由于String是不可变的,所以JVM会自动采用StringBuilder调用append方法把他们拼接起来。


验证

亲测使用IDEA或者使用jdgui工具反编译class文件的结果都是和上述的代码一模一样,也就是无法看出jvm的优化。在网上搜索了许久以后,发现有jad工具可以把jvm优化后的代码展示出来。

下载地址: https://varaneckas.com/jad/

使用方法:

  1. 下载并解压
  2. 添加到环境变量中
  3. 切换到class文件所在目录
  4. 利用指令 jad xxx.class

以下是自己做的一个小实验:

源代码

    public static void main(String[] args) {
        String str = "init";
        for (int i = 0; i < 100000; i++) {
            str += i;
        }
    }

jad工具反编译后的代码

    public static void main(String args[]) {
        String str = "init";
        for(int i = 0; i < 0x186a0; i++)
            str = (new StringBuilder()).append(str).append(i).toString();
    }



总结

从测试可以看出String在进行拼接的时候jvm会根据常量拼接和变量拼接两种情况进行优化。

但值得注意的是,变量拼接的情况下,每次都会new一个新的StringBuilder对象来使用,使用完就会销毁。对象的创建和销毁的开销虽然平时看不出来,可是一旦拼接次数多了的话,这个开销也是十分大的。因此在频繁的字符串变量拼接操作中,尽量由自己显式创建StringBuilder而不要让jvm自己去优化。(避免了jvm预热、5000次拼接的情况下,使用StringBuilder只需要1ms,而直接使用字符串相加则需要64ms)

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值