String對象有三種創建方式:
第一種方式是直接通過賦值語句,將字符串賦值給String類型的變量。
例如:
String str = “Hello”;
第二種方式是通過new運算符,實例化一個String對象,并將對象引用賦值給String類型的變量。
例如:
String str = new String(“Hello”);
第三種方式是通過String對象的intern()方法返回一個String對象的引用。
例如:
String str = “Hello”。 intern();
前面String對象的三種創建方式,虛擬機對其內存分配上是有所區別的,先來看第一種創建方式。
第一種創建方式是通過賦值語句直接將字符串賦值給String類型的變量。在這種創建方式中,虛擬機會在方法區的常量池中判斷是否存在具有和字符串(如Hello)內容相同的String對象:如果常量池不存在和賦值字符串內容相同的對象,虛擬機就在常量池中分配內存并創建該String對象,并將String對象的引用賦值給String類型的變量;如果常量池存在與賦值字符串內容相同的對象,虛擬機會直接將該對象的引用賦值給String類型的變量。這種創建方式對連續創建同一字符串內容的String對象特別有用,內存利用效率非常高效。
第二種創建方式是通過new運算符實例化String對象,并將new運算符返回的對象引用賦值給String類型的變量。在這種創建方式中,虛擬機會創建兩個String對象:一個String對象是在常量池中創建,如果常量池中已有字符串內容相同的對象,則不創建;一個String對象是在運行數據區的堆中創建,將在常量池中創建的String對象的字符數組復制到在堆中創建的String對象。
String類型的變量接收new運算符返回的對象引用后,如果使用賦值語句對該String類型的變量重新賦予不同的字符串內容,該變量將會指向一個新的String對象,該String對象會在常量池中創建。
案例1:建立StringTest1類,在類的main()方法內部,使用new運算符實例化一個String對象,返回的對象引用賦值給String類型的變量str,輸出str指向對象的哈希碼,然后使用賦值語句將新的字符串內容賦值給str,輸出str指向對象的哈希碼,驗證哈希碼是否一致。
在memory包下新建StringTest1類。代碼如下:
publicclassStringTest1 {
/**
* @Title: main
* @Description: Java程序入口main方法
* @returnvoid 返回類型
* @throws
*/
publicstaticvoidmain(String[] args) {
// 實例化String對象
String str = newString(“Hello”);
System.out.println(“str對象的哈希碼:” + str.hashCode());
// 修改str對象的內容
str = “Hello World”;
System.out.println(“str對象修改后的哈希碼:” + str.hashCode());
}
}
程序執行結果如下圖所示:
從程序的執行結果可以看出,當對str重新賦值不同的內容后,虛擬機會在常量池創建一個新的String對象,并將該對象的引用賦值給str。
第三種創建方式是通過String對象的intern()方法來返回一個String對象的引用。在這種創建方式中,虛擬機會首先判斷在常量池中是否存在“Hello”字符串對象,如果存在就直接返回該對象的引用,否則就在常量池創建該對象,并返回對象的引用。
前面String對象的內存分配經常用到常量池,常量池是虛擬機從運行數據區的方法區劃分出來的一塊內存區域,JDK1.8將常量池放置到運行數據區的堆區域。常量池主要用來存儲字面常量、使用final修飾的變量以及符號引用。字面常量包括數值常量(如36、100等)、字符串常量(如“123”、“abc”等)。符號引用是指用一組符號來描述引用的目標,符號可以是任何形式的字面量,只要使用時能夠無歧義的定位到目標即可。例如編譯器會把對象的引用作為一個符號引用,因為編譯器不知道對象引用在內存的實際地址,當虛擬機加載類到運行數據區并初始化類后,虛擬機會把這些符號引用轉換為直接引用(指向目標的內存地址,如對象在堆中的內存地址)。
-
JAVA
+關注
關注
19文章
2960瀏覽量
104563 -
內存分配
+關注
關注
0文章
16瀏覽量
8295 -
string
+關注
關注
0文章
40瀏覽量
4719
發布評論請先 登錄
相關推薦
評論