第四章 初始化清理
1. 重載函數的參數匹配。
a. 傳入的實際參數類型小於方法中聲明的形式參數類型,實際參數的類型就會被提升。但char除外,如果沒有恰好接受char的方法,就會把char提升為int。
b. 傳入的實際參數類型大於方法中聲明的形式參數類型,就得顯示的類型轉換,否則會報錯。但這種窄化轉換會丟失資訊。
2. 在構造器中調用構造器。
如果一個類中有多個構造器,你可以在一個構造器中調用另一個構造器。
如:
注意事項:
a. 你可以用this調用構造器,但你不能用同樣的方法構造兩個構造器;
b. 構造器調用必須置於最起始處;
c. 除構造器外,其他任何方法都不能調用構造器。
3. 終結處理和記憶體回收
記憶體回收行程只知道釋放那些經new分配的記憶體。對於不用new分配的記憶體可在類中定義一個finalize()方法清理。它是在記憶體回收行程準備回收時被調用。但它並不等於析構。
a. 對象不一定總被回收。(一般只有在記憶體耗盡時才運行記憶體回收)
b. 記憶體回收並不等於析構。
c. 記憶體回收只與記憶體相關。
4. 不能將finalize()作為通用的清理方法。
finalize()只用於在分配記憶體時用了類C的做法,如調用了c/c++的代碼,而裡面又用了malloc()等函數來分配記憶體,就得在finalize()方法中調用free()等方法清理。
public class Flower {
int petalCount = 0;
String s = new String("null");
Flower(int petals) {
petalCount = petals;
System.out.println("Constructor w/ int arg only, petalCount= "
+ petalCount);
}
Flower(String ss) {
System.out.println("Constructior w/ String arg only, s=" + ss);
s = ss;
}
Flower(String s, int petals) {
this(petals);
//! this(s); //Can't call two!
this.s = s; //Another use of "this"
System.out.println("String & int args");
}
Flower() {
this("hi", 47);
System.out.println("default constructor (no args)");
}
void print() {
//! this(11); //Not inside non-constructor!
System.out.println("petalCount = " + petalCount + " s = " + s);
}
public static void main(String[] args) {
Flower x = new Flower();
x.print();
}
}
5. 終結條件
終結條件可理解為程式要關閉時必須滿足的條件。如一個程式中的一個對象開啟了一個檔案,那麼在程式結束時所有開啟的檔案應該被關閉。
finalize()方法一個重要的用途就是驗證終結條件。
如:
本例所有的Book對象在被當作記憶體回收前都應該被簽入(check in)。但在main()中有一本沒有。如果沒有finalize()來驗證條件,這個錯誤將很難發現。
6. 類的每個基本類型資料成員保證都會有一個初始值
boolean false
char 0
byte 0
short 0
int 0
long 0
float 0.0
double 0.0
7. 類裡定義一個對象引用時,如果不將其初始化,此引用就會得null值。
8. 與c++不同,類成員變數可在其定義的地方為其賦值。
9. 構造初始化無法阻止自動初始化的進行,它將在構造器被調用前發生。
class Couunter {
int i;
Counter() {
i = 7;
}
}
這裡i 先是0再是7
10. 在類的內部,變數會在任何構造器被調用前得到初始化。
11. 初始化的順序
初始化的順序是先"靜態"對象再"非靜態對象"。
12. 對象的建立過程(假設有個Dog類)
1) 當首次建立類為Dog類的對象時(構造器可看成是靜態方法),或者Dog類的靜態方法/靜態欄位首次被訪問時,Java解譯器必須尋找類路徑,以定位Dog.class檔案。
2) 然後載入Dog.class。有關靜態初始化的所有動作都會執行。因此,靜態初始化只在class對象首次載入的時候執行一次。
3) 當用new Dog()建立對象的時候,首先將在堆上為Dog對象分配足夠的儲存空間。 4)這Block Storage空間會被清零,這就自動地將Dog對象中的所有基本類型資料都設定成了卻省值,而引用則被設定成了null。
5) 執行所有出現於段定義處的初始化動作。
6) 執行構造器。
13. 靜態子句
Java允許將多個靜態初始化動作組織成一個特殊的“靜態子句”如:
class Spoon {
static int i;
static {
i = 47;
}
}
像static{}中的代碼塊就是靜態子句。該代碼塊中的語句只執行一次。
14. 非靜態執行個體初始化子句
和靜態子句一樣,非靜態執行個體初始化也能寫成代碼塊。如:
Dog d1;
Dog d2;
{
d1 = new Dog();
d2 = new Dog();
}
{}中的就是非靜態執行個體初始化子句。
15. 如果數組裡的元素不是基礎資料型別 (Elementary Data Type),那麼必須使用new。否則使用數組中的Null 參考就會產生“異常”
class Book {
boolean checkedOut = false;
Book(boolean checkOut) {
checkedOut = checkOut;
}
void checkIn() {
checkedout = false;
}
public void finalize() {
if(checkedOut)
System.out.println("Error: checked out");
}
}
public class TerminationCondition {
public static void main(String[] args) {
Book novel = new Book(true);
//Proper cleanup
novel.checkIn();
// Drop the reference, forget to clean up
new Book(true);
//Force garbage collection & finalization
System.gc(); //強制進行終結動作
}
}