当前位置 主页 > 服务器问题 > Linux/apache问题 >

    Java 字符串拼接竟然有这么多姿势(收藏版)

    栏目:Linux/apache问题 时间:2019-11-24 13:49

    但扪心自问,在我做程序员的前两年内,我也不知道为啥。遇到字符串拼接就上“+”号操作符,甭管是不是在循环体内。和小菜比起来,我当时可没他这么幸运,还有一位热心的“二哥”能够分享这份价值连城的开发手册。

    既然我这么热心分享,不如好人做到底,对不对?我就认认真真地写一篇文章,给小菜解惑一下。

    01、“+”号操作符

    要说姿势,“+”号操作符必须是字符串拼接最常用的一种了,没有之一。

    String chenmo = "沉默";
    String wanger = "王二";
    
    System.out.println(chenmo + wanger);
    

    我们把这段代码使用 JAD 反编译一下。

    String chenmo = "\u6C89\u9ED8"; // 沉默
    String wanger = "\u738B\u4E8C"; // 王二
    System.out.println((new StringBuilder(String.valueOf(chenmo))).append(wanger).toString());

    我去,原来编译的时候把“+”号操作符替换成了 StringBuilder 的 append 方法。也就是说,“+”号操作符在拼接字符串的时候只是一种形式主义,让开发者使用起来比较简便,代码看起来比较简洁,读起来比较顺畅。算是 Java 的一种语法糖吧。

    02、StringBuilder

    除去“+”号操作符,StringBuilder 的 append 方法就是第二个常用的字符串拼接姿势了。

    先来看一下 StringBuilder 类的 append 方法的源码:

    public StringBuilder append(String str) {
     super.append(str);
     return this;
    }
    

    这 3 行代码没啥可看的,可看的是父类 AbstractStringBuilder 的 append 方法:

    public AbstractStringBuilder append(String str) {
     if (str == null)
      return appendNull();
     int len = str.length();
     ensureCapacityInternal(count + len);
     str.getChars(0, len, value, count);
     count += len;
     return this;
    }
    
    

    1)判断拼接的字符串是不是 null,如果是,当做字符串“null”来处理。appendNull 方法的源码如下:

    private AbstractStringBuilder appendNull() {
     int c = count;
     ensureCapacityInternal(c + 4);
     final char[] value = this.value;
     value[c++] = 'n';
     value[c++] = 'u';
     value[c++] = 'l';
     value[c++] = 'l';
     count = c;
     return this;
    }
    
    

    2)拼接后的字符数组长度是否超过当前值,如果超过,进行扩容并复制。ensureCapacityInternal 方法的源码如下:

    private void ensureCapacityInternal(int minimumCapacity) {
     // overflow-conscious code
     if (minimumCapacity - value.length > 0) {
      value = Arrays.copyOf(value,
        newCapacity(minimumCapacity));
     }
    }

    3)将拼接的字符串 str 复制到目标数组 value 中。

    str.getChars(0, len, value, count)
    

    03、StringBuffer

    先有 StringBuffer 后有 StringBuilder,两者就像是孪生双胞胎,该有的都有,只不过大哥 StringBuffer 因为多呼吸两口新鲜空气,所以是线程安全的。

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

    StringBuffer 类的 append 方法比 StringBuilder 多了一个关键字 synchronized,可暂时忽略 toStringCache = null。

    synchronized 是 Java 中的一个非常容易脸熟的关键字,是一种同步锁。它修饰的方法被称为同步方法,是线程安全的。