深入了解Java字符串常量池

java中有幾種不同的常量池,以下的內容是對java中幾種常量池的介紹以及重點研究一下字符串常量池。

class常量池
我們寫的每一個Java類被編譯后,就會形成一份class文件;class文件中除了包含類的版本、字段、方法、接口等描述信息外,還有一項信息就是常量池(constant pool table),用于存放編譯器生成的各種 字面量 (Literal)和 符號引用 (Symbolic References),每個class文件都有一個class常量池。

其中 字面量 包括:1.文本字符串 2.八種基本類型的值 3.被聲明為final的常量等; 符號引用 包括:1.類和方法的全限定名 2.字段的名稱和描述符 3.方法的名稱和描述符。

運行時常量池
運行時常量池存在于內存中,也就是class常量池被加載到內存之后的版本,是方法區的一部分。不同之處是:它的字面量可以動態的添加(String類的intern()),符號引用可以被解析為直接引用。

JVM在執行某個類的時候,必須經過加載、連接、初始化,而連接又包括驗證、準備、解析三個階段。而當類加載到內存中后,jvm就會將class常量池中的內容存放到運行時常量池中,由此可知,運行時常量池也是每個類都有一個。在解析階段,會把符號引用替換為直接引用,解析的過程會去查詢字符串常量池,也就是我們下面要說的StringTable,以保證運行時常量池所引用的字符串與字符串常量池中是一致的。

字符串常量池
在JDK6.0及之前版本,字符串常量池存放在方法區中在JDK7.0版本以后,字符串常量池被移到了堆中了。至于為什么移到堆內,大概是由于方法區的內存空間太小了。

在HotSpot VM里實現的string pool功能的是一個StringTable類,它是一個Hash表,默認值大小長度是1009;這個StringTable在每個HotSpot VM的實例只有一份,被所有的類共享。字符串常量由一個一個字符組成,放在了StringTable上。

在JDK6.0中,StringTable的長度是固定的,長度就是1009,因此如果放入String Pool中的String非常多,就會造成hash沖突,導致鏈表過長,當調用String#intern()時會需要到鏈表上一個一個找,從而導致性能大幅度下降;在JDK7.0中,StringTable的長度可以通過參數指定。

下面看一下實例:

String s = new String("abc")
這條語句創建了幾個對象?

答案:共2個。第一個對象是”abc”字符串存儲在常量池中,第二個對象在JAVA Heap中的 String 對象。這里不要混淆了s是放在棧里面的指向了Heap堆中的String對象。

比較下列兩種創建字符串的方法:

String str1 = new String("abc");
String str2 = "abc";
答案:第一種是用new()來新建對象的,它會在存放于堆中。每調用一次就會創建一個新的對象。 運行時期創建 。

第二種是先在棧中創建一個對String類的對象引用變量str2,然后通過符號引用去字符串常量池里找有沒有”abc”,如果沒有,則將”abc”存放進字符串常量池,并令str2指向”abc”,如果已經有”abc” 則直接令str2指向“abc”?!癮bc”存于常量池在 編譯期間完成 。

String s1 = new String("s1") ;
String s1 = new String("s1") ;
上面一共創建了幾個對象?

答案:答案:3個 ,編譯期Constant Pool中創建1個,運行期heap中創建2個.(用new創建的每new一次就在堆上創建一個對象,用引號創建的如果在常量池中已有就直接指向,不用創建)

比較字符串的‘==’和‘equals()’區別?

答案:

‘==’ 比較的是變量(棧)內存中存放的對象的(堆)內存地址,用來判斷兩個對象的地址是否相同,即是否是指相同一個對象。比較的是真正意義上的指針操作。注意:

1、比較的是操作符兩端的操作數是否是同一個對象。

2、兩邊的操作數必須是同一類型的(可以是父子類之間)才能編譯通過。

3、引用類型比較的是地址(即是否指向同一個對象),基本數據類型比較的是值,值相等則為true,如:int a=10 與 long b=10L 與 double c=10.0都是相同的(為true),因為他們都指向地址為10的堆。

‘equals()’用來比較的是兩個對象是否相等,由于所有的類都是繼承自java.lang.Object類的,在Object中的基類中定義了一個equals的方法,這個方法的初始行為是比較對象的內存地址,但String類中重寫了equals方法, 比較的是字符串的內容 ,而不再是比較類在堆內存中的存放地址了。

總結:在沒有重寫equals方法的情況下,他們之間的比較還是基于他們在內存中的存放位置的地址值的,因為Object的equals方法也是用雙等號(==)進行比較的,所以比較后的結果跟雙等號(==)的結果相同。String類中重寫了equals方法,變成了字符串內容的比較。

  String s1 = "sss111";
  String s2 = "sss111";
  System.out.println(s1 == s2); //結果為true
  String s1 = new String("sss111");
  String s2 = "sss111";
  System.out.println(s1 == s2); //結果為false
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

結合上面分析,總結如下:向大家推薦一個架構學習交流裙。交流學習裙號:687810532,里面會分享一些資深架構師錄制的視頻錄像

1.單獨使用””引號創建的字符串都是常量,編譯期就已經確定存儲到Constant Pool中;

2.使用new String(“”)創建的對象會存儲到heap中,是運行期新創建的;

3.使用只包含常量的字符串連接符如”aa” + “aa”創建的也是常量,編譯期就能確定,已經確定存儲到String Pool中,String pool中存有“aaaa”;但不會存有“aa”。

4.使用包含變量的字符串連接符如”aa” + s1創建的對象是運行期才創建的,存儲在heap中;只要s1是變量,不論s1指向池中的字符串對象還是堆中的字符串對象,運行期s1 + “aa”操作實際上是編譯器創建了StringBuilder對象進行了append操作后通過toString()返回了一個字符串對象存在heap上。

5.String s2 = “aa” + s1; String s3 = “aa” + s1; 這種情況,雖然s2,s3都是指向了使用包含變量的字符串連接符如”aa” + s1創建的存在堆上的對象,并且都是s1 + “aa”。但是卻指向兩個不同的對象,兩行代碼實際上在堆上new出了兩個StringBuilder對象來進行append操作。在Thinking in java一書中285頁的例子也可以說明。

6.對于final String s2 = “111”。s2是一個用final修飾的變量,在編譯期已知,在運行s2+”aa”時直接用常量“111”來代替s2。所以s2+”aa”等效于“111”+ “aa”。在編譯期就已經生成的字符串對象“111aa”存放在常量池中。

?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 229,908評論 6 541
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 99,324評論 3 429
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事?!?“怎么了?”我有些...
    開封第一講書人閱讀 178,018評論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,675評論 1 317
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,417評論 6 412
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,783評論 1 329
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,779評論 3 446
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,960評論 0 290
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,522評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,267評論 3 358
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,471評論 1 374
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,009評論 5 363
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,698評論 3 348
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,099評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,386評論 1 294
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,204評論 3 398
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,436評論 2 378

推薦閱讀更多精彩內容

  • 從網上復制的,看別人的比較全面,自己搬過來,方便以后查找。原鏈接:https://www.cnblogs.com/...
    lxtyp閱讀 1,355評論 0 9
  • 本文是我自己在秋招復習時的讀書筆記,整理的知識點,也是為了防止忘記,尊重勞動成果,轉載注明出處哦!如果你也喜歡,那...
    波波波先森閱讀 844評論 1 6
  • package cn.itcast_01;/* 字符串:就是由多個字符組成的一串數據。也可以看成是一個字符數組。 ...
    蛋炒飯_By閱讀 600評論 0 0
  • java中有幾種不同的常量池,以下的內容是對java中幾種常量池的介紹以及重點研究一下字符串常量池。 class常...
    Lyria_Tailver閱讀 986評論 0 0
  • 前言 RTFSC (Read the fucking source code )才是生活中最重要的。我們天天就是要...
    二毛_coder閱讀 462評論 1 1