為了加深對Java語言的理解披泪,加深對Java各種特性的理解與掌握,平常會自己歸納一些專題的分析和總結(jié)菊匿「杜唬基于自己的理解计福,感覺哪些部分適合在一起進(jìn)行總結(jié)跌捆,就歸納為一個專題了∠笥保可能一個專題里面的東西也不屬于一個類別佩厚,或者也比較雜亂,請見諒说订。
本文是在總結(jié)不可變對象與String的不可變中抄瓦,涉及到的String的字符串常量池潮瓶。感覺這個部分比較重要,面試也經(jīng)掣奇ⅲ考到這些毯辅,就單獨(dú)拿出來作為一個專題。(此篇總結(jié)大部分是借鑒了CSDN的一篇文章煞额,然后加上了一些自己的理解)
字符串常量池:
- 為了減少在jvm中創(chuàng)建的字符串的數(shù)量思恐,字符串類維護(hù)了一個字符串常量池,字符串常量池(String pool)是Java堆內(nèi)存中一個特殊的存儲區(qū)域膊毁;
- 當(dāng)創(chuàng)建String對象時胀莹,jvm會先檢查字符串常量池,如果這個字符串的常量值已經(jīng)存在在池中了婚温,就直接返回池中對象的引用描焰,如果不在池中,就會實(shí)例化一個字符串并放入池中栅螟;
- 常量池:用于保存java在編譯期就已經(jīng)確定的荆秦,已經(jīng)編譯的class文件中的一份數(shù)據(jù)。包括了類力图、方法萄凤、接口中的常量,也包括字符串常量搪哪,如String s = "a"這種聲明方式靡努;
String s1 = "aaa";
String s2 = "aaa";
從日常的面試題展開:
String s = new String("abc"); //創(chuàng)建了幾個對象
兩個;
第一個對象是"abc"字符串存儲在常量池中晓折;
第二個對象是創(chuàng)建在Heap中的String對象惑朦;這里的s是放在棧里面的指向了Heap堆中的String對象。
String s1 = new String("s1") ;
String s2 = new String("s1") ; //創(chuàng)建了幾個對象
三個漓概;
第一個是編譯期就已經(jīng)創(chuàng)建在常量池中創(chuàng)建的"s1"漾月,因?yàn)閯?chuàng)建一個之后常量池中就會有,不再創(chuàng)建胃珍,直接指向梁肿;
后面兩個是運(yùn)行期使用new創(chuàng)建在堆上的s1和s2;
示例1:
String s0 = "111"; //pool
String s1 = new String("111"); //heap
final String s2 = "111"; //pool
String s3 = "sss111"; //pool
String s4 = "sss" + "111"; //pool
String s5 = "sss" + s0; //heap
String s6 = "sss" + s1; //heap
String s7 = "sss" + s2; //pool
String s8 = "sss" + s0; //heap
System.out.println(s3 == s4); //true
System.out.println(s3 == s5); //false
System.out.println(s3 == s6); //false
System.out.println(s3 == s7); //true
System.out.println(s5 == s6); //false
System.out.println(s5 == s8); //false
示例2:
String str1 = "abc";
String str2 = "abc";
String str3 = "abc";
String str4 = new String("abc");
String str5 = new String("abc");
String str6 = new String("abc");
結(jié)論:
- 單獨(dú)使用""引號創(chuàng)建的字符串都是常量觅彰,編譯器就已經(jīng)存儲到常量池中了吩蔑;
- 使用new String()創(chuàng)建的是對象會存儲到heap中,是運(yùn)行期創(chuàng)建的填抬;
- 使用只包含常量的字符串連接符如"a"+"a"創(chuàng)建的也是常量烛芬,編譯器就能確定,并存儲到常量池"aa",但不會有"a"存在赘娄;
- 使用包含變量的字符串連接符如"a"+s1創(chuàng)建的對象會存儲在堆中仆潮,運(yùn)行時期才創(chuàng)建;只要s1是變量遣臼,不論s1指向池常量池中的字符串對象還是堆中的字符串對象性置,運(yùn)行期"a"+s1操作實(shí)際上是編譯器創(chuàng)建了StringBuilder對象進(jìn)行了append操作后通過toString()返回了一個字符串對象存在heap上。
- 對于final String s2 = "111"揍堰,是一個用final修飾的變量蚌讼,在編譯期就已知了,在包含變量的字符串連接符"a"+s2時直接用常量"111"來代替s2个榕,等效于"a"+"111"篡石,在編譯期就已經(jīng)生產(chǎn)了字符串對象"a111"對象在常量池中。
目前全部文章列表:
idea整合restful風(fēng)格的ssm框架(一)
idea整合restful風(fēng)格的ssm框架(二)
idea整合spring boot+spring mvc+mybatis框架
idea整合springboot+redis
JVM學(xué)習(xí)之—Java內(nèi)存區(qū)域
JVM學(xué)習(xí)之—垃圾回收與內(nèi)存分配策略
專題整理之—不可變對象與String的不可變
專題整理之—String的字符串常量池