首先,必須強調一點:String Pool不是在堆區,也不是在棧區,而是存在於方法區(Method Area)java
解析:程序員
String Pool是常量池(Constant Pool)中的一塊。數組
咱們知道,常量就是不能夠再改變的值,給它建一個池子很明顯是爲了加快程序運行的速度;在一個程序中,常量和變量是相對存在的;變量由於可變性因此通常存在於棧中,而常量去做爲一個特殊羣體被存在在常量池中。安全
常量池(constant pool)指的是在編譯期被肯定,並被保存在已編譯的.class文件中的一些數據。--- (很明顯在方法區)數據結構
它包括了關於類、方法、接口等中的常量,也包括字符串常量(這個就是Sring Pool啦)。jvm
在編譯好的class文件中,有個區域稱爲Constant Pool,它是一個由數組組成的表,類型爲cp_info constant_pool[],用來存儲程序中使用的各類常量,包括Class/String/Integer等各類基本Java數據類型。性能
======= ================ui
上面這些,簡單理解:一個Class類,它裏面有常量的存在,好比 int a=10;String b="123450";它們在JVM看來就是常量(固然在方法中可能被修改啦),在Class被加載時,JVM特地都把它放在一個數組中維護起來,而且把該數組放在方法區中,起名叫常量池。spa
常量池存在於方法區,它包含各類類型的常量(8個基本數據類型,包裝類型等)線程
咱們把常量池中的String Pool中的常量做爲對象來看待 --- 由於String就是對象,String類型的常量天然也是對象啦!
好比:
String str1 = new String("Hello");
它建立了2個對象,一個是堆中的String對象,一個是String Pool中的String對象。
要理解Java中String的運做方式,必須明確一點:String是一個非可變類(immutable)。什麼是非可變類呢?簡單說來,非可變類的實例是不能被修改的,每一個實例中包含的信息都必須在該實例建立的時候就提供出來,而且在對象的整個生存週期內固定不變。Java爲何要把String設計爲非可變類呢?你能夠問問 james Gosling :)。可是非可變類確實有着自身的優點,如狀態單一,對象簡單,便於維護。其次,該類對象對象本質上是線程安全的,不要求同步。此外用戶能夠共享非可變對象,甚至能夠共享它們的內部信息。(詳見 《Effective java》item 13)。String類在java中被大量運用,甚至在class文件中都有其身影,所以將其設計爲簡單輕便的非可變類是比較合適的。
1、建立。
好了,知道String是非可變類之後,咱們能夠進一步瞭解String的構造方式了。建立一個Stirng對象,主要就有如下兩種方式:
雖然兩個語句都是返回一個String對象的引用,可是jvm對二者的處理方式是不同的。對於第一種,jvm會立刻在heap中建立一個String對象,而後將該對象的引用返回給用戶。對於第二種,jvm首先會在內部維護的String Pool中經過String的 equals 方法查找是對象池中是否存放有該String對象,若是有,則返回已有的String對象給用戶,而不會在heap中從新建立一個新的String對象;若是對象池中沒有該String對象,jvm則在heap中建立新的String對象,將其引用返回給用戶,同時將該引用添加至String Pool中。注意:使用第一種方法建立對象時,jvm是不會主動把該對象放到String Pool
裏面的,除非程序調用 String的intern方法。看下面的例子:
再看下面的例子:
爲何jvm能夠這樣處理String對象呢?就是由於String的非可變性。既然所引用的對象一旦建立就永不更改,那麼多個引用共用一個對象時互不影響。
2、串接(Concatenation)。
java程序員應該都知道濫用String的串接操做符是會影響程序的性能的。性能問題從何而來呢?歸根結底就是String類的非可變性。既然String對象都是非可變的,也就是對象一旦建立了就不可以改變其內在狀態了,可是串接操做明顯是要增加字符串的,也就是要改變String的內部狀態,二者出現了矛盾。怎麼辦呢?要維護String的非可變性,只好在串接完成後新建一個String 對象來表示新產生的字符串了。也就是說,每一次執行串接操做都會致使新對象的產生,若是串接操做執行很頻繁,就會致使大量對象的建立,性能問題也就隨之而來了。
爲了解決這個問題,jdk爲String類提供了一個可變的配套類,StringBuffer。使用StringBuffer對象,因爲該類是可變的,串接時僅僅時改變了內部數據結構,而不會建立新的對象,所以性能上有很大的提升。針對單線程,jdk 5.0還提供了StringBuilder類,在單線程環境下,因爲不用考慮同步問題,使用該類使性能獲得進一步的提升。
3、String的長度 咱們可使用串接操做符獲得一個長度更長的字符串,那麼,String對象最多能容納多少字符呢?查看String的源代碼咱們能夠得知類String中是使用域 count 來記錄對象字符的數量,而count 的類型爲 int,所以,咱們能夠推測最長的長度爲 2^32,也就是4G。 不過,咱們在編寫源代碼的時候,若是使用 Sting str = "aaaa";的形式定義一個字符串,那麼雙引號裏面的ASCII字符最多隻能有 65534 個。爲何呢?由於在class文件的規範中, CONSTANT_Utf8_info表中使用一個16位的無符號整數來記錄字符串的長度的,最多能表示 65536個字節,而java class 文件是使用一種變體UTF-8格式來存放字符的,null值使用兩個字節來表示,所以只剩下 65536- 2 = 65534個字節。也正是變體UTF-8的緣由,若是字符串中含有中文等非ASCII字符,那麼雙引號中字符的數量會更少(一箇中文字符佔用三個字節)。若是超出這個數量,在編譯的時候編譯器會報錯。