• 不能用 + 拼接字符串? 这次我要吊打面试官!


    好久没维护《吊打面试官》系列了,今天再来一篇,这次真的要吊打了,哈哈!(看往期吊打系列请在后台回复:吊打,我会陆续更新……)

    我们做 Java 程序员以来,不管是工作当中,还是面试过程中,都知道:字符串拼接不能用 String,要用 StringBuilder 或者是 StringBuffer,以至于它们都被滥用了。

    StringBuilder、StringBuffer 简称:SB,下文统一用 SB 代替。

    SB它们都是可变的字符串,它们之间的区别也是 Java 初中级面试战场上出现几率十分高的一道题,上场率没有 90% 也有 80% 吧。

    这两个的具体区别请看这篇文章

    我们反过来想下,String真的是不可变的么?不一定,看下:Java 中的 String 真的是不可变的吗?这篇。

    当然,本文不是讨论字符串可变与不可变的问题,而是讨论:字符串拼接一定要用 SB 吗?为什么不能用 + ?能不能用 + ?什么时候可以用 +

    为什么不能用 + 号拼接字符串?我不服,接下来我要吊打面试官!

    什么时候不能用 +

    通过多个表达式完成一个字符串拼接操作。

    private void test1() {
        String www = "www.";
        String str = www;
        str += "javastack.";
        str += "com";
    }
    

    字节码如下:

    // access flags 0xA
    private static test2()V
    L0
    LINENUMBER 14 L0
    LDC "www."
    ASTORE 0
    L1
    LINENUMBER 15 L1
    ALOAD 0
    ASTORE 1
    L2
    LINENUMBER 16 L2
    NEW java/lang/StringBuilder
    DUP
    INVOKESPECIAL java/lang/StringBuilder.<init> ()V
    ALOAD 1
    INVOKEVIRTUAL java/lang/StringBuilder.append (Ljava/lang/String;)Ljava/lang/StringBuilder;
    LDC "javastack."
    INVOKEVIRTUAL java/lang/StringBuilder.append (Ljava/lang/String;)Ljava/lang/StringBuilder;
    INVOKEVIRTUAL java/lang/StringBuilder.toString ()Ljava/lang/String;
    ASTORE 1
    L3
    LINENUMBER 17 L3
    NEW java/lang/StringBuilder
    DUP
    INVOKESPECIAL java/lang/StringBuilder.<init> ()V
    ALOAD 1
    INVOKEVIRTUAL java/lang/StringBuilder.append (Ljava/lang/String;)Ljava/lang/StringBuilder;
    LDC "com"
    INVOKEVIRTUAL java/lang/StringBuilder.append (Ljava/lang/String;)Ljava/lang/StringBuilder;
    INVOKEVIRTUAL java/lang/StringBuilder.toString ()Ljava/lang/String;
    ASTORE 1
    L4
    LINENUMBER 18 L4
    RETURN
    L5
    LOCALVARIABLE www Ljava/lang/String; L1 L5 0
    LOCALVARIABLE str Ljava/lang/String; L2 L5 1
    MAXSTACK = 2
    MAXLOCALS = 2
    

    不会查看字节码的,看这里,就会了。

    观察下,NEW java/lang/StringBuilder 出现了两次,是因为我们在代码中拼接了两次,也就是说每一次拼接操作都会创建一次 StringBuilder

    如果我们是在一个循环中进行字符串拼接,那是不是一次拼接就要创建一个 StringBuilder

    wtf……这哪能接受!频繁创建对象是有性能开销的,这也是为什么我们常说的字符串不能用 + 拼接,而要用那两个 SB 拼接了。

    什么时候可以用 +

    直接将三个字面量的字符串拼接成一个字符串。

    private static void test2() {
        String str = "www." + "javastack." + "com";
    }
    

    字节码如下:

    // access flags 0x2
    private test2()V
    L0
    LINENUMBER 13 L0
    LDC "www.javastack.com"
    ASTORE 1
    L1
    LINENUMBER 14 L1
    RETURN
    L2
    LOCALVARIABLE this Lcom/test/jdk/TestSB; L0 L2 0
    LOCALVARIABLE str Ljava/lang/String; L1 L2 1
    MAXSTACK = 1
    MAXLOCALS = 2
    

    从字节码看出,没有任何创建 StringBuilder 的指令,直接从常量池进行取出一个完整的字符串:www.javastack.com。很明显,这是 Java 编译器对代码进行了优化。

    所以,通过这个示例告诉你,在这种情况下是可以用 + 号进行字符串拼接的。

    这个示例可以演变成我们实际工作当中的某个 SQL 语句拼接的案例,如:

    String sql = "select name, sex, age, address"
            + "from t_user"
            + "where age > 18";
    

    别说这样不行,这样是行的。

    但你要是换成这样就不行了:

    String sql = "select name, sex, age, address";
    sql += "from t_user";
    sql += "where age > 18";
    

    这样又回到创建多个 StringBuilder 的时候了。

    也就是说,在一个表达式中完成字符串拼接是可以用 + 号完成的,因为编译器已经做了优化。

    小结一下

    你只需要记住这两点:

    1、在循环和多个表达式中不能 +,频繁创建 SB 性能影响;

    2、在单个表达式中可以用 +,编译器直接做了优化;

    老铁们,都搞清楚了?

    这个观点有没有被误解很久?

    下次面试,把这篇内容亮出来,吊打面试官,没问题的。

    有收获的朋友一定要点个在看,这样我写原创更带劲了,谢了,老铁们。

  • 相关阅读:
    结构体位域与规范定义顺序的问题
    visual studio 2015使用MFC的console调试打印
    MFC笔记
    MFC中解决文本保存到文件时乱码问题
    C/C++关于文件的读写操作以及文件的打开和保存
    MFC使用自定义消息
    MFC输入框CEdit控件十六进制转换
    Visual studio C++ MFC应用程序自动探测串口号
    visual C++ MFC串口编程overlapped结构汇总
    模块及模块间的接口方式
  • 原文地址:https://www.cnblogs.com/javastack/p/12082503.html
Copyright © 2020-2023  润新知