美文网首页
2019-09-05

2019-09-05

作者: 清风乀月 | 来源:发表于2019-09-16 16:51 被阅读0次

    作者来源1
    作者来源2

    一、字符串拼接方式:+和concat和StringBuilder

    源码:

    public static void main(String[] args) {
    
            String str = "";
    
            System.out.println("执行加号拼接:");
            long starttime = System.currentTimeMillis();
            System.out.println("执行拼接之前的时间:"+starttime);
            for (int i = 0; i < 50000; i++) {
                str += "a";
            }
            long latertime = System.currentTimeMillis();
            System.out.println("执行拼接之后的时间:"+latertime);
            System.out.println("用加号拼接所花费的时间:"+(latertime - starttime));
            System.out.println("result== " + str);
            System.out.println("--------------------------------");
    
    
            String str1 = "";
            System.out.println("执行concat拼接:");
            long starttime1 = System.currentTimeMillis();
            System.out.println("执行拼接之前的时间:"+starttime1);
            for (int i = 0; i < 50000; i++) {
                str1 = str1.concat("b");
            }
            long latertime1 = System.currentTimeMillis();
            System.out.println("执行拼接之后的时间:"+latertime1);
            System.out.println("用加号拼接所花费的时间:"+(latertime1 - starttime1));
            System.out.println("result=="+str1);
            System.out.println("--------------------------------");
    
            StringBuilder stringBuilder = new StringBuilder();
            System.out.println("执行StringBuilder拼接:");
            long starttime2 = System.currentTimeMillis();
            System.out.println("执行拼接之前的时间:"+starttime2);
            for (int i = 0; i < 50000; i++) {
                stringBuilder.append("c");
            }
            long latertime2 = System.currentTimeMillis();
            System.out.println("执行拼接之后的时间:"+latertime2);
            System.out.println("用加号拼接所花费的时间:"+(latertime2 - starttime2));
            System.out.println("result=="+stringBuilder.toString());
    
    
        }
    

    执行结果图:


    image.png

    由此可见,StringBuilder最快,concat次之,加号拼接最慢。

    二、为什么会出现这样的情况

    2.1 "+"方法实现原理

    内部实现采用StringBuilder的append方法进行追加,最终以toString方法转换成String字符串,比如:

    String wechat = "Hollis";
    String introduce = "每日更新Java相关技术文章";
    String hollis = wechat + "," + introduce;
    

    反编译后的结果如下,反编译工具为jad。

    String wechat = "Hollis";
    String introduce = "\u6BCF\u65E5\u66F4\u65B0Java\u76F8\u5173\u6280\u672F\u6587\u7AE0";
    String hollis = (new StringBuilder()).append(wechat).append(",").append(introduce).toString();
    

    通过查看反编译后的代码,我们可以发现,在拼接字符串常量中,是将String转成了StringBuilder后,使用其append方法进行处理,也就是说,,在java中使用“+”对字符串拼接,采用的原理是使用StringBuilder。
    但是它与纯粹使用StringBuilder的append方法是不同的:
    1、每次执行循环添加字符时,它都会创建一个StringBuilder对象,
    2、每次执行完后都会调用toString方法将其转换为字符串
    所以耗费了更多时间。

    2.2 "concat"方法实现原理

    concat源代码

        public String concat(String str) {
            int otherLen = str.length();//获取添加的字符串长度
            if (otherLen == 0) {//如果字符串长度为0,则返回字符串长度本身
                return this;
            }
            int len = value.length;//获取原字符串的字符数组的长度
            char buf[] = Arrays.copyOf(value, len + otherLen);//将原字符串的字符数组放到buff数组中
            str.getChars(buf, len);//追加的字符串转化成字符数组,添加到buf中
            return new String(buf, true);//产生一个新的字符串返回
        }
    

    整体的实现过程就是完成对数组的拷贝,虽然在内存中处理是原子性操作,速度非常快,但是,最后的return语句创建一个新的String对象,也就是每次concat操作都会创建一个新的String对象,这也是限制concat方法速度的原因。

    2.3 "append"方法实现原理

    代码实现

        public AbstractStringBuilder append(String str) {
            if (str == null)//如果是null值,则把null作为字符串处理
                return appendNull();
            int len = str.length();
            ensureCapacityInternal(count + len);//追加后的字符数组长度是否超过当前值
            str.getChars(0, len, value, count);//将字符串复制到目标数组
            count += len;
            return this;
        }
    
        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'; //将null添加到char[] value数组中
            count = c; //将count的值初始化
            return this;//返回结果
        }
    
        private void ensureCapacityInternal(int minimumCapacity) {
            // overflow-conscious code
            if (minimumCapacity - value.length > 0) {
                value = Arrays.copyOf(value,
                        newCapacity(minimumCapacity));//加长数组空间,并作数组拷贝
            }
        }
    

    append方法都在做字符数组的处理,加长,拷贝等,这些都是基本的数据处理,整个方法内并没有生成对象,只是最后执行了toString方法返回了一个对象而已

    三、题外

    String str = "My name is ";
    str = str + "JTZen9";
    

    相当于str = new StringBuilder(str).append("JTZen9").toString();
    也就是说,该str = str + "JTZen9",语句执行完后,总共有三个对象

    String str = "My name is " + "JTZen9";
    

    JVM会直接把str作为一个对象,即“My name is JTZen9”

    四、使用场景

    1、大多数情况,我们使用“+”,符合编码习惯和我们的阅读
    2、当在频繁进行字符串的运算(如拼接、替换、删除等),或者在系统性能临界的时候,我们可以考虑使用concat或append方法

    相关文章

      网友评论

          本文标题:2019-09-05

          本文链接:https://www.haomeiwen.com/subject/hsidyctx.html