深入浅出Java基础——字符串拼接

字符串拼接(jdk8)

public static void main(String[] args) {
    	String str1 = "string";
        代码1.  String str2 = str1 + "merge";
        代码2.  String str3 = "string" + "merge1"; 
}

字符串拼接可以说是我们日常中的基本操作中的基本操作,就是两个 String 对象相加一下就完事了。可你有没有想过,两个对象怎么能相加呢,对象存储的不是内存地址吗?Java 是如何帮助我们将字符串进行拼接的呢?

带着这两个疑问,我们对上面的代码进行反编译:

public static void main(java.lang.String[]);
    Code:
       0: ldc           #2                  创建String对象,将对象压入栈顶// String string
       2: astore_1
       3: new           #3                  new 指令// class java/lang/StringBuilder
       6: dup
       7: invokespecial #4                  调用StringBuilder无参构造,创建对象// Method java/lang/StringBuilder."<init>":()V
      10: aload_1
      11: invokevirtual #5                  调用StringBuilder::append()方法,拼接 string// Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      14: ldc           #6                  // String merge
      16: invokevirtual #5                  调用StringBuilder::append()方法,拼接 merge// Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      19: invokevirtual #7                  调用StringBuilder::toString()方法,创建String对象 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
      22: astore_2
      23: ldc           #8                  创建String对象// String stringmerge1
      25: astore_3
      26: return
}

代码1:通过反编译我们首先可以看到String str2 = str1 + "merge";对应的反编译结果,当字符串需要进行拼接时,JVM 帮助我们创建了 StringBuilder 对象,并通过调用 append 方法拼接字符串对象。这是 java 提供的一种优化操作(语法糖),用于减少代码量并提高可读性,我们写出的简略代码,经过 javac 编译,经历语义分析和字节码生成,将 String 的拼接操作替换为 StringBuilder 或 StringBuffer 的 append() 操作。

类似的语法糖还有泛型,自动装箱拆箱,for-each 迭代等等。

PS: 在 JDK 9,JVM 将以上的拼接优化操作改变为:通过执行 invokedynamic 字节码指令动态的反射调用字符串拼接方法。

代码2:通过反编译我们可以看到String str3 = "string" + "merge1"; 只对应了两行字节码指令,分别是 ldc 创建 String 对象并将该对象压入操作数栈顶,astore 弹出栈顶元素并赋值给局部变量 str3。为什么这行代码没有进行字符串拼接呢,不是中间有个加号吗?这是因为在 javac 编译优化中有个操作叫 常量折叠优化

javac 编译器在编译 String str3 = "string" + "merge1";时,可以清楚的看到结果,所以将代码优化为 String str3 = "stringmerge1";。即将字面量 string 与 merge1 合并为一个字面量 stringmerge1。

常量折叠优化只针对 String 及基本数据类型。例如a = 1 + 2 会被优化为a = 3

为什么StringBuilder、StringBuffer 比 String 快

每当我们直接使用 + 拼接字符串时,JVM 都会新创建一个 StringBuilder 并调用 append 方法。所以直接使用 StringBuilder 减少了创建对象的步骤,节省了空间以及时间。

还有一种字符串拼接方法

String::concat()方法,String 类提供的拼接字符串方法。

public String concat(String str) {
    int otherLen = str.length();
    if (otherLen == 0) {
        return this;
    }
    int len = value.length;
    char buf[] = Arrays.copyOf(value, len + otherLen);
    str.getChars(buf, len);
    return new String(buf, true);
}

concat 方法中通过 Arrays.copyOf 方法新创建了一个名为 buf 的char数组用于存储拼接后的字符串,将新的字符串拼接在数组后面,最后通过 new String(char[])的方式创建新的 String 并返回。 每次拼接都要新创建 String 对象,效率很低。

为什么要创建新的 String 呢,不可以修改原来的吗?

因为 String 是不可变类,它不向外提供修改内部属性的方法。String 不可变的好处

String 与基本数据类型拼接

试着猜测下面代码的输出结果

public static void main(String[] args) {
        System.out.println( 5 + 5 + " 5 + 5 ");
        System.out.println(" 5 + 5 " + 5 + 5);
        System.out.println(" 5 + 5 " + (5 + 5));
    }



10 5 + 5 
 5 + 5 55
 5 + 5 10

不难,稍加注意即可。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值