读帖有感。
今天看到一篇博客是讲解String,以及String使用堆、栈、常量池。讲的和仔细,很透彻,很接近底层,有一定的难度。
原贴:https://www.iteye.com/topic/522167
学到的:
想理解String和堆、栈、常量池这三者之间的关系就必须清楚拘留字符串对象。
拘留池(其中的常量字符就是拘留字符串对象)
公共语言运行库会自动维护一个名为“拘留池”(intern pool) 的表,它包含程序中以编程方式声明或创建的每个唯一的字符串的一个引用。因此,具有特定值的字符串的实例在系统中只有一个。
//代码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"在堆中创建了一个拘留字符串( 值得注意的是:如果源程序中还有一个"Hello world"字符串常量,那么他们都对应了同一个堆中的拘留字符串)。然后用这个拘留字符串的值来初始化堆中用new指令创建出来的新的String对象,局部变量sa实际上存储的是new出来的堆对象地址。此时在JVM管理的堆中,有两个相同字符串值的String对象:一个是拘留字符串对象,一个是new新建的字符串对象。
String sb=new String("Hello world"); 去执行的时候,去拘留池中比较有"Hello world",然后用此拘留对象来初始化堆中new出来的新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中。
String s="abcd"; 执行:而局部变量s存储的是常量池中"abcd"所对应的拘留字符串对象的地址(sab和s存的地址不同)
代码2:
String sd="abcd"; "ab"+"cd"会直接在编译期就合并成常量"abcd", 因此相同字面值常量"abcd"所对应的是同一个拘留字符串对象,
String(大姐,出生于JDK1.0时代) 不可变字符序列
StringBuffer(二姐,出生于JDK1.0时代) 线程安全的可变字符序列
StringBuilder(小妹,出生于JDK1.5时代) 非线程安全的可变字符序列