字串的不可變性(String的不可變性)Integer的常量池
阿新 • • 發佈:2018-11-15
JVM的記憶體分配圖:
PC暫存器:會記錄各個執行緒的執行位置
Java方法棧:面向java方法
本地方法棧:面向本地方法(用C++ 寫的native方法)
方法區:載入後的Java類會被存放在java方法區,程式碼實際執行的時候,虛擬機器會執行方法區內的程式碼。
為什麼字串是不可變的?
因為字串的底層使用的是陣列儲存,陣列的長度是不可變的。且使用final,private修飾,不能直接方法,String也沒有提供直接修改的方法。
由此我們知道:String一旦被建立,則不能被修改,所謂的修改也只是建立了新的物件。
字串常量在記憶體中的位置:
字串常量物件儲存在常量池中,jdk1.6及之前在方法區中,jdk1.7之後堆中特殊的區域中;jdk1.8,在元空間中(元空間是方法區的一種體現)
String str1 = new String(“hello”);
String str2 = “hello”;
System.out.println(str1 == str2);//false;
第一句程式碼建立了幾個物件?
字串常量池中有一個物件,堆中有一個字串物件; 堆中的字串物件指向了常量池中常量物件的"hello";str1,str2在棧中; new String("hello")在堆中;"hello"字串常量在常量池中
為什麼是false?
str1引用在棧中,指向了堆中的物件,str2引用在棧中指向常量池(方法區),兩者的地址是不一樣的。 請注意:字串常量中的字串也是物件,堆中的字串物件都是指向了字串常量池中的物件的。
String str1 = "hellojava";
String str2 = "hello" +"java";
System.out.println(str1 == str2);//true
為什麼是true?
hellojava作為一個字串(常量)物件在字串常量池中存在,java編譯器發現hello和java是兩個常量, 是字串的拼接,拼接之後仍然是字串常量物件,依然儲存在常量池中,發現常量池中有這個常量物件, 直接將棧中的引用str2指向該存在的常量物件。這裡的注意:沒有涉及到變數的運算,相同的字串不會產生新的物件
String str1 = "hello";
String str2 = "java";
String str3 = "hellojava";
String str4 = str1 + "java";
String str5 = str1 + str2;
System.out.println(str3 == str4);//false
System.out.println(str3 == str5);//false
為什麼是這個結果?
詳解:str1指向常量池中的常量物件hello str2指向常量池中的常量物件java,str3指向常量池中的常量物件hellojava。str4 和 str5 都涉及到了String物件,實際會產生新的物件儲存在堆中,而str3 指向的是常量池(方法區中) 總結:變數參與運算(拼接),一定會產生新的物件。物件在堆中
關於String物件的圖解
(1)
(2)
任何的型別都有常量池的概念,比如說
比如下面的程式碼:
package hello_java;
public class Test {
public static void main(String[] args) {
Integer i1 = 127;
Integer i2 = 127;
Integer i3 = 128;
Integer i4 = 128;
System.out.println(i1 == i2);
System.out.println(i3 == i4);
}
}
true
false
為甚呢?看下面的原始碼,重新建立一個Integer的物件的時候,首先看值的範圍,如果在該方位內的話,就使用常量池中的值。
public static Integer valueOf(int i) {
if (i >= IntegerCache.low && i <= IntegerCache.high)
return IntegerCache.cache[i + (-IntegerCache.low)];
return new Integer(i);
}