JAVA中的字符串對象池

一:引出問題

在學習字符串的兩種比較方式時發現了一個現象,進行一下總結;

String str1 = "kaka";
Srting str2 = "kaka";
System.out.println(str1 == str2); //true

在之前的學習中,String類型被認爲是引用類型,是存放在堆中的,因此在使用"=="判斷時,他會將堆內存地址一併進行判斷,應該是返回false的,爲什麼返回了true???。

二:String的兩種實例化方式

1:直接賦值
此種方式是最常用的

String str = "kaka";

2:使用String的構造方法

String str = new String("kaka");

那麼這兩種方式有什麼不同呢?

三:引入字符串對象池進行區分

其實開始的問題的造成原因根本上就是由於字符串對象池(String Pool)的存在造成的。
JVM爲了提高性能和效率,防止不必要的重複創建造成的內存空間的浪費和不斷的銷燬造成的性能下降,因此創建了String Pool。那麼這個字符串對象池是如何提高效率的呢?
1:使用直接賦值
開始的問題中使用直接賦值的形式進行創建的兩個字符串變量。使用"=="進行判斷時,會返回true,這就說明這兩個值"hello"是來自於同一塊內存空間。這是因爲在使用直接賦值的方式實例化字符串變量時,是擁有了對象池的處理功能的。
這個對象池相比較於其他的對象new後在堆中開闢的獨立的內存空間,他是公用的。因此

String str1 = "kaka";
Srting str2 = "kaka";

str1在創建了kaka這個字符串對象後,就直接自動的執行入池操作。在創建str2時,他會先在字符串對象池中先進行查找看有是否相同內容的字符串對象。若沒有創建,若有則直接引用。
以上就解釋了爲什麼在使用"=="後會返回true。
2:使用構造方法

String str1 = new String("hello");
String str2 = new String("hello");
System.out.println(str1 == str2);//false

在java中使用new就代表着在堆中開闢的內存空間,而str1,和str2就是在堆中開闢了兩個不同的堆內存空間進行存儲相同的內容。因此他們的地址是不同的,因此返回false。
在這裏插入圖片描述
如何將使用構造方法創建的字符串變量也放入池中?
使用方法intern()方法

String str1 = new String("hello").intern();
String str2 = new String("hello").intern();
System.out.println(str1 == str2);   //true

四:靜態對象池和運行時對象池

說到這不得不說一下常量池,常量池的兩種狀態的區分主要是 在於常量和變量的區分
1:靜態對象池(靜態常量池)
編譯形成的.class文件是用來進行先期的內存分配的,他所有的操作內容都會以常量的形式進行出現。

String str1 = "hello" + "World";
String str2 = "helloWorld";
System.out.println(str1 == str2);   //  true

str1的字符串中的兩個常量的拼接是在編譯時期執行的,在編譯期結束後他的存在將不會以多個常量的形式存在,而是以一個整體常量存在。在編譯期後存在的都是經過修飾的。
而且在編譯結束後,字符串對象就會被自動放在了String Pool中了。
2:運行時對象池(運行時常量池)
在運行時期的數據內容並不是固定的,他可能是通過變量保存的。因此他的內容是無法固定的。

String midTemp = "World";
String str1 = "hello" + midTemp;
String str2 = "helloWorld";
System.out.println(str1 == str2); // false

在上述代碼的第二行是使用的變量進行的拼接,因此在編譯期,他是無法進行拼接成功的,導致無法放入String Pool。在編譯期中執行了字符串的拼接之後,他會在堆中開闢新的內存空間,也就不會有相同的內存地址,因此會返回false。

四:總結

剛開始準備開始後端工作,以上只是將基礎的概念區分一下,並沒有深入的了結。如有錯誤還請指出。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章