阅读帖子。
我今天看到一篇博客解释了 String 以及 String 如何使用堆、堆栈和常量池。讲的很仔细,很透彻,很接近底线,有一定难度。
原帖:
学习:
如果要了解String与堆、栈、常量池的关系,就必须要清楚的留字String对象。
实习生池(其中常量字符是实习生字符串对象)
公共语言运行时自动维护一个称为“实习池”的表,其中包含对程序中以编程方式声明或创建的每个唯一字符串的引用。因此,系统中只有一个具有特定值的字符串实例。
//代码1
String sa=new String("Hello world");
String sb=new String("Hello world");
System.out.println(sa==sb); // false
//代码2
String sc="Hello world";
String sd="Hello world";
System.out.println(sc==sd); // true
如博客中所述:
在代码 1 中:
String sa=new String("Hello world");开始执行,JVM已经在堆中为“Hello world”创建了一个detained string(值得注意的是,如果源程序中有一个“Hello world”字符串常量拘留通知书的序列码是干嘛用,那么它们都对应同一个heap中的detained strings) 然后用滞留字符串的值来初始化堆中new指令创建的新String对象。局部变量 sa 实际上存储了新堆对象的地址。此时,在JVM管理的堆中,存在两个字符串值相同的String对象:一个是被扣留的字符串对象,另一个是新创建的字符串对象。
String sb=new String("Hello world");执行时,滞留池中有“Hello world”,然后用这个detain对象从堆中初始化新的String对象,然后将地址存入sb。
所以 sa 和 sb 不一样。 (在堆中初始化后,有两个新的String对象)
在代码 2 中:
局部变量sc存储已经创建了滞留字符串地址的堆。比较sc运行的时候,用滞留字符串对象拘留通知书的序列码是干嘛用,直接保存对象地址
所以两者是一样的。
用 + 分析。
//代码1
String sa = "ab";
String sb = "cd";
String sab=sa+sb;
String s="abcd";
System.out.println(sab==s); // false
//代码2
String sc="ab"+"cd";
String sd="abcd";
System.out.println(sc==sd); //true
代码 1:
局部变量sa、sb存储了堆中两个滞留字符串对象的地址。 sa+sb执行时,JVM会先在堆中创建一个StringBuilder类,同时用sa指向的滞留字符串对象完成初始化,然后调用append方法完成滞留的合并操作sb指向的字符串,然后调用StringBuilder的toString()方法在堆中创建一个String对象,最后将新生成的String对象的堆地址存放在局部变量sab中。
字符串 s="abcd";执行:并且局部变量s存储了“abcd”对应的滞留字符串对象在常量池中的地址(sab和s中存储的地址不同)
代码 2:
字符串 sd="abcd"; “ab”+“cd”会在编译时直接合并成常量“abcd”,所以同一个字面常量“abcd”对应同一个滞留字符串对象,
String(大姐,诞生于JDK1.0时代)不可变字符序列
StringBuffer(二姐,诞生于JDK1.0时代)线程安全的变量字符序列
StringBuilder(小妹,诞生于JDK1.5时代)非线程安全的变量字符序列