【jvm关于String】先上代码
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语言规范
里面的内容)- 1、通过常量表达式运算得到的字符串是在编译时计算得出的, 并且之后会将其当作字面常量对待.
- 2、在运行时通过连接运算得到的字符串是新创建的, 因此会区别对待.
- 3、如果显示地限定运算得到的字符串, 得到的结果与任何之前存在的具有相同内容的字面常量字符串是相同的字符串.
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);
}