為了加深對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的字符串常量池