zoukankan      html  css  js  c++  java
  • String的运算 重载"+"与StringBuilder

    参考《think in Java》第四版 第十三章 13.2 重载“+”与StringBuilder

    上原书代码:

    public class Concatenation{
        public static void main(String args[]){
           String mango =  "mango";
           String str = "abc" + mango + "deg" + 47;
           System.out.println(str);                 
        }    
    }    

    .class文件 反编译 

    javac Concatenation.java

    javap -c Concatenation

    结论:等同于new StringBuilder().append("abc").append(mango).append("deg").append(47).toString();

    思考:常见的一个问题String Str = "a" + "b" + "c";生成了几个String对象,或者生成了几个对象。

    看《think in java》的例子很容易进入误区:new StringBuilder.append("a").append("b").append("c");下面看个例子:

    public class StringTest{
        public static void main(String args[]){
            String str = "a" + "b" + "c";
            String str2 = str + "d" + "f";
    String str3 = str + "d" + "f" + 47 + "g"; } }

    可以看出 String str = "a" + "b" = “c”; 在编译期直接编译成String str = "abc";

    后面String Str2 = str + "d" + "f";在编译期编译成String str2 = new StringBuilder().append("abc").append("df").toString();

    后面String Str3 = str + "d" + "f" + 47 +"g";在编译期编译成String str2 = new StringBuilder().append("abc").append("d").append(47).append("g").toString();

    为什么

    java编译期有应用到“合并已知量”的优化技术。

         这里我去找了下编译原理关于代码优化相关的知识

    代码优化的分类:

    根据设计程序范围分类:全局优化,局部优化,循环优化

    根据技术的分类:

    删除多余运算:对于相同的子表达式,在第一次出现时进行计算,且值计算一次,其结果带入ti,以后重复的地方直接带入ti,不重复运算,节约时间及空间

    强度削弱:在不改变运算结果的前提下,将程序中执行时间长的运算替换成执行时间短的运算。x^3可用x*x*x实现

    合并已知量:若参加运算的两个量都是已知量,则在编译时直接计算出结果。1+2编译期直接3

    复写传播:尽量不引用那些程序中只传递信息而不改变值,不影响运行结果的变量。

    循环优化:将循环中的不变量提到循环外面。

    所以String str = "a' +“b” +"c";合并已知量为String str = "abc";

    其实《think in java》中在提到final关键字时有一段话,表明java编译时应用了此技术:

    一个永不改变的编译期常量:对于编译期常量这种情况,编译期可以将该常量值带入到任何可能运用到的计算式中,也就是说可以在编译时执行计算式,减轻运行时的负担,但这类常量必须是基本数据类型,且必须final修饰初始化。

    所以综上,不结合上下文String Str2 = str + "d" + "f"中str是未知的。编译时优化为StringBuilder,有趣的是后面的“d”+"f"合并了,然后str3中我们看到了并没有合并为"df47e"

     String str = "a" + "b" + "c";编译为String str = "abc"; 建立了一个String对象“abc”。

    另外查找资料的时候发现一个名词StringPool(字符串常量池)

    由于java对String操作频繁,所以对String类做了很多优化,StringPool就是其中之一,StringPool是运行期维护于常量池中,处于GC永久代。

    创建String对象的两种方式

    String str = new String("aa");
    String str = "aa";

    "aa"会存入StringPool,当下次使用时“aa”,String会先到StringPool查找“aa”,找到了把地址赋给引用对象,也就是指向同一对象(内存),没找到建立新对象。

    String str = "a";
    String str2 = "a";
    System.out.println(str == str2);//true

    当然无论何时,new 一个对象都会创建一个新的对象。

    拓展;Integer类的cache机制

  • 相关阅读:
    Linux 技巧
    设计模式大集合
    [Java] Design Pattern:Code Shape
    [Java] 设计模式: Code Shape
    BookNote: Refactoring
    读书笔记: 博弈论导论
    读书笔记: 博弈论导论
    读书笔记: 博弈论导论
    读书笔记: 博弈论导论
    读书笔记: 博弈论导论
  • 原文地址:https://www.cnblogs.com/wqff-biubiu/p/9167346.html
Copyright © 2011-2022 走看看