• String的'+'的性能及原理


    逛了几个论坛。

    不少人在讨论String的“+”,StringBuilder与StringBuffer等一系列的问题。先不多说了了

    现分类详述:

    1、String的‘+’,底层运行。及效率问题

    2、StringBilder与StringBuffer的比較


    本篇博文先介绍第一个问题

    为了让大家看明确,

    我们举例说明吧!

    为了加深理解,我们能够来做几个小实验。



    javac Test         编译文件
    javap -c Test   查看虚拟机指令

    实验一:纯字符串

    public class Test {
        public static void main(String args[]) {
            String str = "a";
        }
    }

    // 将字符串 a 存入常数池
       0:   ldc     #2; //String a
       // 将引用存放到 1 号局部变量中
       2:   astore_1
       3:   return

    实验二:纯字符串相加

    public class Test {
        public static void main(String args[]) {
            String str = "a" + "b";
        }
    }


       // 将字符串 ab 压入常数池
       0:   ldc     #2; //String ab
       2:   astore_1
       3:   return

    实验二能够非常明显地看出,编译器在编译时产生的字节码已经将 "a" + "b" 优化成了 "ab",
    同理多个字符串的相加也会被优化处理,须要注意的是字符串常量相加

    实验三:字符串与自己主动提升常量相加

    public class Test {
        public static void main(String args[]) {
            String str = "a" + (1 + 2);
        }
    }
    // 将字符串 a3 压入常数池
       0:   ldc     #2; //String a3
       2:   astore_1
       3:   return

    通过虚拟机指令能够看出,1 + 2 自己主动提升后的常量与字符串常量,虚拟机也会对其进行优化。



    实验二、实验三结论:常量间的相加并不会引起效率问题

    实验四:字符串与变量相加

    public class Test {
        public static void main(String args[]) {
            String s = "b";
            String str = "a" + s;
        }
    }
    // 将字符串 b 压入常数池
       0:   ldc     #2; //String b
       // 将引用存放到 1 号局部变量中
       2:   astore_1
       // 检查到很量的相加。这时创建 StringBuilder 对象
       3:   new     #3; //class java/lang/StringBuilder
       // 从栈中复制出数据。即把字符串 b 复制出来
       6:   dup
       // 调用 StringBuilder 的初始构造
       7:   invokespecial   #4; //Method java/lang/StringBuilder."<init>":()V
       // 将字符串 a 压入常数池
       10:  ldc     #5; //String a
       // 调用 StringBuilder 的 append 方法,把字符串 a 加入进去
       12:  invokevirtual   #6; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
       // 从 1 号局部变量中载入数据引用
       15:  aload_1
       // 调用 StringBuilder 的 append 方法,把字符串 b 加入进去
       16:  invokevirtual   #6; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
       // 调用 StringBuilder 的 toString 方法
       19:  invokevirtual   #7; //Method java/lang/StringBuilder.toString:()Ljava/lang/String;
       // 将 toString 的结果保存至 2 号局部变量
       22:  astore_2
       23:  return

    实验四能够看出,很量字会串相加时,因为相加的变量中存放的是字符串的地址引用。
    由于在编译时无法确切地知道其它详细的值,也就没有办法对其进行优化处理,这时为了
    达到连接的效果,其内部採用了 StringBuilder 的机制进行处理(JDK 5 中新增的,我
    这里没有 JDK 1.4,预计在 JDK 1.4 下採用的是 StringBuffer),将他们都 append
    进去,最后用 toString 输出。



    若 s 为其它类型时,比方:int 类型,也是採用同种方式进行处理。

    同理。依据实验二的结果,在 String str = "a" + "b" + s; 时。先会优化成 "ab" 再与
    s 依据实验四的方式进行处理。这时 StringBuilder 仅调用了两次 append 方法。

    假设是 String str = "a" + s + "b"; 这样的形式的就没办法优化了。StringBuilder 得调
    用三次 append 方法。

    实验四的结论表明,字符串与变量相加时在内部产生了 StringBuilder 对象并採取了一定
    的操作。

    假设仅仅有一句 String str = "a" + s; 这样子的,其效率与
    String str = new StringBuilder().append("a").append(s).toString();
    是一样的。

    一般所说的 String 採用连接运算符(+)效率低下主要产生在下面的情况中:

    public class Test {
        public static void main(String args[]) {
            String s = null;
            for(int i = 0; i < 100; i++) {
                s += "a";
            }
        }
    }
    每做一次 + 就产生个 StringBuilder 对象,然后 append 后就扔掉。下次循环再到达时重
    新产生个 StringBuilder 对象。然后 append 字符串,如此循环直至结束。



    假设我们直接採用 StringBuilder 对象进行 append 的话,我们能够节省 N - 1 次创建和
    销毁对象的时间。




  • 相关阅读:
    对拍源码QwQ
    BZOJ-3875: [Ahoi2014&Jsoi2014]骑士游戏(SPFA+DP)
    2017年10月19日23:31:57
    BZOJ-1064: [Noi2008]假面舞会 (综合性图论题)
    BZOJ-1002: [FJOI2007]轮状病毒(打表找规律or递推 + 高精度)
    BZOJ1397 Ural 1486 Equal squares
    BZOJ3417 Poi2013 Tales of seafaring
    BZOJ2286 [Sdoi2011消耗战
    BZOJ1370 [Baltic2003]Gang团伙
    BZOJ2530 [Poi2011]Party
  • 原文地址:https://www.cnblogs.com/gavanwanggw/p/7134241.html
Copyright © 2020-2023  润新知