字符拼接的深入理解

简介: 字符拼接的深入理解

字符串拼接在日常中编码中大量使用,但是对底层的原理却缺乏理解。

我们还是从一段代码开始:

public static void main(String[] args) throws Exception{
        String s1="a";
        String s2="b";
        String s3="ab";
        String s4=s1+s2;
        System.out.println(s3==s4);
    }

运行输出:

false

我们反编译字节码看看:

javap -v Jvm1_22

选取关键部分:

        0: ldc           #2                  // String a
         2: astore_1
         3: ldc           #3                  // String b
         5: astore_2
         6: ldc           #4                  // String ab
         8: astore_3
         9: new           #5                  // class java/lang/StringBuilder
        12: dup //复制一份对象引用到栈顶
        13: invokespecial #6                  // Method java/lang/StringBuilder."<init>":()V 执行构造方法
        16: aload_1
        17: invokevirtual #7                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
        20: aload_2
        21: invokevirtual #7                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
        24: invokevirtual #8                  // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
        27: astore        4
        29: getstatic     #9                  // Field java/lang/System.out:Ljava/io/PrintStream;

我们解读如下:

前面字符串"a" “b” "ab"的生成没啥问题,我们关注 String s4=s1+s2的执行过程,

从第9-13行,我们看到new 关键字,其实是创建了StringBuilder对象

16行加载了第一个槽位中的数a

17行调用了append的操作

10行加载了第二个槽位中的数,21行调用了append的操作

24行调用了tostring的方法,27行则把对象进行保存。

我们再进一步看StringBuilder中的toString方法:

 @Override
    public String toString() {
        // Create a copy, don't share the array
        return new String(value, 0, count);
    }

可以很清楚看到,这里会利用拼接好的值new一个新的String对象,所以我们最终拼接的结果会是一个新对象,这就是a+b的生成过程,可以很好解释s3==s4结果是false。

总结

字符串的+ 拼接操作其实底层会调用StringBuilder拼接一个新的字符串对象出来,有new的操作,返回的是一个新的对象。

进一步理解

我们看看另一种情况:

 public static void main(String[] args) throws Exception{
        String s1="a";//用到了这个对象,才开始创建这个对象,行为上面是懒惰的
        String s2="b";
        String s3="ab";

        String s4=s1+s2;
        System.out.println(s3==s4);
        String s5="a"+"b"; 
        System.out.println(s5==s3);
    }

反编译结果如下:

  32: aload_3
        33: aload         4
        35: if_acmpne     42
        38: iconst_1
        39: goto          43
        42: iconst_0
        43: invokevirtual #10                 // Method java/io/PrintStream.println:(Z)V
        46: ldc           #4                  // String ab
        48: astore        5
        50: getstatic     #9                  // Field java/lang/System.out:Ljava/io/PrintStream;
        53: aload         5

我们看到46行,字符串直接就取了ab的值,自然输出结果就是true。

这里的解释是javac在编译期的优化,它认为"a" “b"都是常量,拼接的结果在编译期间就确定为"ab”,不可能再变回了,上一行代码是引用的值,有可能发现修改。

目录
相关文章
|
C语言
带你快速了解字符(串)函数(一)
带你快速了解字符(串)函数(一)
|
1天前
|
开发框架 .NET 程序员
C# 去掉字符串最后一个字符的 4 种方法
在实际业务中,我们经常会遇到在循环中拼接字符串的场景,循环结束之后拼接得到的字符串的最后一个字符往往需要去掉,看看 C# 提供了哪4种方法可以高效去掉字符串的最后一个字符
|
3月前
|
C#
C# 中的字符与字符串
C# 中的字符与字符串
|
4月前
|
索引 Python
字符串:比较、拼接、切割、转义字符;相关切割、替换、查找、去除空白、转大小写函数的方法
字符串:比较、拼接、切割、转义字符;相关切割、替换、查找、去除空白、转大小写函数的方法
31 0
带你快速了解字符(串)函数(二)
带你快速了解字符(串)函数(二)
带你快速了解字符(串)函数(三)
带你快速了解字符(串)函数(三)
|
算法
利用切片操作去除字符串空格
利用切片操作去除字符串空格
52 0