例子:
String str1 = "a" + "b" + "c"; //記憶體位址1(常量池:編譯時已轉換為"abc")
String str2 = "abc"; //記憶體位址1(常量池)
String str3 = "ab";//(常量池)
final String str4 = "ab"; //(常量池)
String str5 = str3 + "c"; //記憶體位址3(堆記憶體:由于編譯的時候不能确定str3的值,是以利用StringBuffer拼接字元串)
String str6 = str4 + "c"; //記憶體位址1(常量池:由于str4用final定義,則不可以修改,是以編譯時直接拼接為"abc")
String str7 = new String("abc"); //記憶體位址4(堆記憶體)
String str8 = new String(str2); //記憶體位址5(堆記憶體)
Log.i(TAG, "str1 == str2 " + (str1 == str2)); //true
Log.i(TAG, "str1.equals(str2) " + str1.equals(str2) + "\n"); //true
Log.i(TAG, "str1 == str5 " + (str1 == str5)); //false
Log.i(TAG, "str1.equals(str5) " + str1.equals(str5) + "\n"); //true
Log.i(TAG, "str1 == str6 " + (str1 == str6)); //true
Log.i(TAG, "str1.equals(str6) " + str1.equals(str6) + "\n"); //true
Log.i(TAG, "str1 == str7 " + (str1 == str7)); //false
Log.i(TAG, "str1.equals(str7) " + str1.equals(str7) + "\n"); //true
Log.i(TAG, "str1 == str8 " + (str1 == str8)); //false
Log.i(TAG, "str1.equals(str8) " + str1.equals(str8) + "\n"); //true
Log.i(TAG, "str7 == str8 " + (str7 == str8)); //false
Log.i(TAG, "str7.equals(str8) " + str7.equals(str8) + "\n"); //true
列印結果:
05-30 17:48:44.051 3057-3057/ str1 == str2 true
05-30 17:48:44.051 3057-3057/ str1.equals(str2) true
05-30 17:48:44.051 3057-3057/ str1 == str5 false
05-30 17:48:44.051 3057-3057/ str1.equals(str5) true
05-30 17:48:44.051 3057-3057/ str1 == str6 true
05-30 17:48:44.051 3057-3057/ str1.equals(str6) true
05-30 17:48:44.051 3057-3057/ str1 == str7 false
05-30 17:48:44.051 3057-3057/ str1.equals(str7) true
05-30 17:48:44.051 3057-3057/ str1 == str8 false
05-30 17:48:44.051 3057-3057/ str1.equals(str8) true
05-30 17:48:44.051 3057-3057/ str7 == str8 false
05-30 17:48:44.051 3057-3057/ str7.equals(str8) true
分析:
個人了解:
常量池:常量存放區域,友善對象重複利用。
棧:定義的屬性存放區域
堆:new出來的對象存放的區域
方法區:存放靜态變量,靜态代碼塊等
1.str1分析:
String str1 = "a" + "b" + "c";
"a" + "b" + "c"在編譯的時候,會被編譯器優化為"abc",存在于常量池。
記憶體關系:棧記憶體的變量str1的指針指向于常量池的字元串"abc"。
2.str2分析:
String str2 = "abc";
"abc",存在于常量池,str2存在于棧記憶體
記憶體關系:棧記憶體的變量str2的指針指向于常量池的字元串"abc"。
3.str5分析:
String str3 = "ab";
String str5 = str3 + "c";
由于str3是一個變量,是以在編譯期間jvm,并不能将直接轉換為字元串"abc",而是首先建立一個StringBuilder類,再
用StringBuilder類的append方法将str3和字元串"c"拼接,最後通過StringBuilder的toString()方法傳回一個
String指派給str5,因為字元串"abc"是new出來的是以存在于堆記憶體。
記憶體關系:棧記憶體的變量str5的指針指向于堆記憶體的String對象,堆記憶體的String對象指針指向于常量池的字元串對象"abc"。
4.str6分析:
final String str4 = "ab";
String str6 = str4 + "c";
由于變量str4被final修飾,意味着不能修改,是以編譯器在編譯階段就會将str4 + "c"簡化為字元串"abc",]存在于常
量池。
記憶體關系:棧記憶體變量str6的指針指向常量池的字元串"abc"。
5.str7分析:
String str7 = new String("abc");
首先編譯器會在常量池當中尋找是否有字元串"abc",假如沒有,則會在常量池當中建立字元串"abc",new String("abc")
調用了String類的參數為String的構造方法,這個方法最主要做的事情就是建立一個String對象,并且将"abc"的值淺拷貝
一份給String對象,接着将String對象指派給str7。
記憶體關系:棧記憶體變量str7的指針指向堆記憶體的String對象,堆記憶體的String對象指向常量池的"abc"對象。
6.str8分析:
String str2 = "abc"; //記憶體位址1(常量池)
String str8 = new String(str2);
由于String str2 = "abc";在前面已經确認了字元串"abc"已經在常量池建立了,是以當代碼運作到String = str8這句代
碼的時候,會建立一個String對象,并且String對象的指針指向于常量池的字元串"abc"。
記憶體關系:棧記憶體變量str8的指針指向堆記憶體的String對象,對記憶體的String對象指向于常量池的"abc"對象。
由以上分析可知:str1的記憶體位址 == str2的記憶體位址 == str6的記憶體位址。
str1 != str5 != str7 != str8
str5,str7,str8的記憶體位址各不同。但是str1,str2,str6,str7,str8的值的記憶體位址一緻都是為常量池當中的"abc",
隻有str5的值的記憶體位址在堆記憶體 。
注:如有不對,請指出,謝謝。