《Java內存分配》
Java內存分配和管理是Java的核心技術之一。涉及以下:棧、堆、常量池、靜態域。
1. 常量池:constant pool。指在編譯期被確定,並被保存在已編譯的.class文件中的一些數據。是個有序集合,以表的形式。主要包括:
a) 用final定義的常量。可以是基本數據類型(int、long等),也可是對象型(數組等)。
b) 類、接口、字段、方法的名字和描述符。
注意的是,String作爲特殊的類型,若初始化方式是String a = "abc",則"abc"是存於常量池中的,即String字符串是不可變的。而String a = new String("abc")則不同。
2. 靜態域:存放在隊形中用static定義的成員。
3. 棧:使用上特點是讀取速度快,但是隻能存定長的、不可變的數據。
當在一段代碼塊定義一個變量時,Java就在棧中爲這個變量分配內存空間;當該變量退出該作用域後,Java會自動釋放掉爲該變量所分配的內存空間,該內存空間立即被另作他用。主要包括:
a) 基本數據類型的變量及其數據。
eg:int a = 9。a和9都存在棧中,並且a指向9。注意,當同時有int b = 9時,則只存入b並指向9;當a的值改變,如下面有a = 10,則存入10並讓a指向10。基本數據變量的這種儲存方式,與引用變量完全不同。
b) 引用數據類型(即,對象)的引用變量。
引用變量是一個內存地址(Java指針),指向該對象在堆中儲存的數據的首地址。
4. 堆:用來存放new出來的對象和數組。
引用變量在程序運行到其該作用域之外時,Java會自動釋放掉棧中的引用變量;注意,堆中的數據不會立即被釋放;在堆中分配的內存,由GC(JVM垃圾自動回收器)來不定期回收。
5. String的存儲方式:String包裝類比較特殊,跟基本數據類型和對象的存儲方式都不同,而且初始化方式、“+”連接運算符等會有特殊的處理方式。
初始化時,其引用存於棧,但是數據可能存放在常量池中(編譯時就已創建好),有的存放在堆中(運行時才被創建)。
eg:String a = "hello";
String b = "hello";
System.out.println(a == b); //true
上例,這種初始化方式,"hello"存放於常量池中,a和b都指向它。
eg:String a = new String("hello");
String b = new String ("hello");
System.out.println(a == b); //false
System.out.println(a.equals(b)); //true
上例,兩次初始化new了兩個對象,堆中沒有常量池或棧的那種機制,不會判斷兩次new的對象的數據是否相等,所以是false。
注意:a.equals(b)取決於是否重寫了equals方法,Object類的默認equals()方法比較的就是a == b;String重寫了equals方法。
6. 值傳遞和引用傳遞:跟上述內存分配機制密切相關,總結爲:
a. 值傳遞(傳遞的是拷貝):基本數據類型 和 String的直接複製情況。(即常量池)
b. 引用傳遞(傳遞的是引用&指針&內存地址):引用數據類型。