一、String在內存中的存儲情況
1.Java虛擬機JVM的內存塊及其變量、對象內存空間是怎麼存儲分配的?
1、棧:存放基本數據類型及對象變量的引用,對象本身不存放於棧中而是存放於堆中 1)、基礎類型 byte (8位)、boolean (1位)、char (16位)、int (32位)、short (16位)、float (32位)、double (64位)、long (64位) 2)、java代碼作用域中定義一個變量時,則java就在棧中爲這個變量分配內存空間,當該變量退出該作用域時,java會自動釋放該變量所佔的空間 2、堆:new操作符的對象 1)、new創建的對象和數組 2)、在堆中分配的內存,由Java虛擬機的自動垃圾回收器來管理 3、靜態域:static定義的靜態成員變量 4、常量池:存放常量 |
package terry.java.base;
public class StringTest {
public static void main(String[] args) {
String a = "hello";
String b = "hello";
String newA = new String("hello");
String newB = new String("hello");
System.out.println("****** Testing Object == ******");
System.out.println("a==b ? :" + (a==b));
System.out.println("newA==newB ? :" +(newA==newB));
System.out.println("a==newA ? :" + (a==newA));
System.out.println("***** Testing String Object intern method******");
System.out.println("a.intern()==b.intern() ? : " + (a.intern()==b.intern()));
System.out.println("newA.intern()==newB.intern() ? :" + (newA.intern()==newB.intern()));
System.out.println("a.intern()==newA.intern() ? :" + (a.intern()==newA.intern()));
System.out.println("a=a.intern() ? :" + (a==a.intern()));
System.out.println("newA==newA.intern() ? : " + (newA==newA.intern()));
System.out.println("****** Testing String Object equals method******");
System.out.println("equals() method :" + a.equals(newA));
String c = "hel";
String d = "lo";
final String finalc = "hel";
final String finalgetc = getc();
System.out.println("****** Testing Object splice ******");
System.out.println("a==\"hel\"+\"lo\" ? :" + (a=="hel"+"lo"));
System.out.println("a==c+d ? : " + (a==c+d));
System.out.println("a==c+\"lo\" ? : " + (a==c+"lo"));
System.out.println("a==finalc+\"lo\" ? :" + (a==finalc+"lo"));
System.out.println("a==finalgetc+\"lo\" ? :" + (a==finalgetc+"lo"));
}
private static String getc(){
return "hel";
}
}
********************Testing Object ************************
(1)a、b 創建的 hello 都存在於方法區中的常量池其中的字符串池,故第一條 true 。
(2) newA、newB 創建的 hello 存在於堆中,指向不同的對象,故 false 。
(3)a 創建的 hello 存在於方法區中的常量池其中的字符串池,而 newA 創建的 hello 存在於堆中,故false 。
******************Testing intern method********************
當調用 intern 方法時,如果池已經包含一個等於此 String 對象的字符串(該對象由 equals(Object) 方法確定),則返回池中的字符串。否則,將此 String 對象添加到池中,並且返回此 String 對象的引用。
(1)都指向字符串常量池中的hello,所以true
(2)都指向字符串常量池中的hello,所以true
(3)都指向字符串常量池中的hello,所以true
(4)都指向字符串常量池中的hello,所以true
(5)newA指向堆中的hello對象,newA.intern()指向字符串常量池中的hello,所以爲false;
*********************Testing equals method**********************
equals方法檢測兩個字符串的內容是否相同,而==運算符檢測兩個字符串是否放置在同一個位置上。
(1)a和newA內容相同,所以true;
**********************Testing Object splice**************************
(1) "hel" + "lo"的創建是先進行表達式的字符串連接,然後才進行賦值。賦值的時候會搜索池中是否有 hello 字符串,若有則指向該字符串,若沒有則在池中新增該字符串。顯然 “hel” + "lo" 的創建是用了a 已經創建好的字面量,故 true 。
(2) a == c + d ?; 其實相當於 a== new String(c + d) ?; new String(c + d) 是存放於堆中的,不是字面量。所以 false 。
(3)JVM對於字符串引用,由於在字符串的"+"連接中,有字符串引用存在,而引用的值在程序編譯期是無法確定的,所以c+\"lo\"實際是c在棧中保存的地址+字符串"lo"於常量池中指向的地址 所指向的在堆中新分配的一塊內存空間,所以false
(4)對於final修飾的變量,它在編譯時被解析爲常量值的一個本地拷貝存儲到自己的常量 池中或嵌入到它的字節碼流中,在編譯期就已經確定了內存空間地址,所以此類似於2個字符串常量的+ ,所以true
****** Testing Object == ******
a==b ? :true
newA==newB ? :false
a==newA ? :false
***** Testing String Object intern method******
a.intern()==b.intern() ? : true
newA.intern()==newB.intern() ? :true
a.intern()==newA.intern() ? :true
a==a.intern() ? :true
newA==newA.intern() ? : false
****** Testing String Object equals method******
equals() method :true
****** Testing Object splice ******
a=="hel"+"lo" ? :true
a==c+d ? : false
a==c+"lo" ? : false
a==finalc+"lo" ? :true
a==finalgetc+"lo" ? :false
上述各個變量及引用在JVM分配的內存情況