jvm关于String

2019-06-02  本文已影响0人  冉桓彬

先上代码

public class Test   {
    public void test(){
        String a = "a";
        String b = "b";
        String c = "ab";
        String d = a + b;
        String e = "a"+"b";
        Log.v("AndroidTest","c==d:"+(c==d));
        Log.v("AndroidTest","c==e:"+(c==e));
    }
}

输出结果为

06-02 22:22:46.043 1779-1779/? V/AndroidTest: c==d: false
06-02 22:22:46.043 1779-1779/? V/AndroidTest: c==e: true

接下来先复制一段概念:
凡是编译期能推断出值内容的字符串, 都会在编译时期编程字符串常量, 从而享有上面代码中提到的共享对象的待遇, 而运算中间插入了变量, 让编译器认为只有运行时才能判断其内容的字符串, 则会在运行时产生新的对象.

编译期优化(复制粘贴java语言规范里面的内容)

针对上面的结论打开Test.java编译之后得到的Test.class文件

package androidtest.myapplication;
import android.util.Log;
public class Test {
    public Test() {}
    public void test() {
        String a = "a";
        String b = "b";
        String c = "ab";
        // a+b在编译成字节码时, 会通过StringBuilder.append的方式, 然后再通过toString()获取
        // 对应的字符串结果, 而StringBuilder.toString又是使用new String方式创建了字符串.
        String d = (new StringBuilder()).append(a).append(b).toString();
        // 对应上面代码, 可以看出在编译成字节码文件时, 进行了编译优化, e直接被合并成了"ab",
        // 也就是说在实际运行时, c在字符串常量池中创建一个"ab"的字符串常量, 然后e会直接从字
        // 符串常量池中获取已有的常量"ab".
        String e = "ab";
        Log.v("AndroidTest", (new StringBuilder()).append("c==d:").append(c == d).toString());
        Log.v("AndroidTest", (new StringBuilder()).append("c==e:").append(c == e).toString());
    }
}

StringBuilder.toString

@Override
public String toString() {
    // 创建新的字符串, 并没有复用字符串常量池中已有的"ab".
    return new String(value, 0, count);
}
上一篇下一篇

猜你喜欢

热点阅读