1. 程式人生 > >Java程式設計思想第四版讀書筆記——第五章 初始化與清理

Java程式設計思想第四版讀書筆記——第五章 初始化與清理

第五章 初始化與清理

1 用構造器確保初始化

使用構造器(condructor),在建立物件時初始化。分為帶引數的初始化和不帶引數的初始化。

2 方法過載

型別提升(向上提升):int — long — float — double

                    byte — short — int 

                    char — int 

窄化轉換:和向上提升反過來,注意先考慮降到byte再考慮char

3 預設構造器

沒有構造器的時候,系統會自動生成一個無參的預設構造器。如果寫了構造器,就別指望系統生成了,所以如果寫了帶參構造器,就不能無參初始化了。

4 this關鍵字

this關鍵字只能在方法內部使用,表示對“呼叫方法的那個物件”的引用。

儘管可以用this呼叫一個構造器,但不能呼叫兩個。當在一個構造器中呼叫另一個構造器時,需要用到this關鍵字。

如下:

      Flower(int petals) {            petalCount = petals;            print("Constructor w/ int arg only, petalCount= "              + petalCount);         }         Flower(String s, int petals) {            this(petals);       //!      this(s); // Can’t call two!            this.s = s; // Another use of "this"            print("String & int args");         } 

除構造器外,編譯器禁止在其他任何方法中呼叫構造器。

static方法是沒有this的方法。所以有些人認為static方法不是“面向物件”的,這個概念還是有爭議的。

5 清理:終結處理和垃圾回收

垃圾回收器只知道釋放那些經由new分配的記憶體。

1、物件可能不被垃圾回收。

2、垃圾回收不等於“析構”。

3、垃圾回收只與記憶體有關(使用垃圾回收器的唯一原因就是回收程式不再使用的記憶體)。

不應該將finalize()作為統一的清理方法,因為它可能不被執行,這是一個陷阱。

無論是“垃圾回收”還是“終結”,都不保證一定會發生。

finalize()還有一個有趣的用法,它並不依賴於每次都要對finalize()進行呼叫,這就是物件“終結條件”的驗證。

System.gc() 用於強制進行終結動作。比如

強制進入finalize(隨著程式的執行也許程式自己也會呼叫這個方法),當某個關係的標記量有異,打印出來。可供程式設計師找出程式程式碼尤其是建立物件時隱晦的缺陷。

垃圾回收器如何工作:

Java虛擬機器採用一種自適應的垃圾回收技術。

要是沒有新垃圾及產生,就會轉換到 "標記——清掃"工作模式。

"標記——清掃"所依據的思路同樣是從堆疊和靜態儲存區出發,遍歷所有的引用,進而找出存活的物件,給物件一個標記。全部標記工作完成後,清理動作才會開始。

“停止——複製”的回收動作不是在後臺執行的,它發生時,程式將會被暫停。它將所有活物件從舊堆複製到新堆,然後再釋放舊堆中的物件所佔記憶體。

如果所有物件都很穩定,垃圾回收器的效率降低,就切換到“標記——清掃”方式,同樣,Java虛擬機器會追蹤“標記——清掃”的效果,如果堆空間出現很多碎片,就會切換回“停止——複製”方式。

Java虛擬機器中有很多附加技術提升速度,比如“即時”編譯器技術。這種技術將程式全部或部分翻譯成本地機器碼。

6 成員的初始化

所有變數在使用前都能得到適當的初始化。對於函式區域性變數,Java以編譯錯誤的形式強制初始化。不初始化編譯就不成功。下面是各型別基本資料的初始值

 boolean            false       char               [ ]       byte               0       short              0       int                0       long               0       float              0.0       double             0.0       reference          null 

7 構造器的初始化

無法阻止自動初始化的進行,它將在構造器被呼叫之前發生。因此,編譯器不會強制一定在構造器某個地方或者在使用它們之前對元素進行初始化——因為初始化早已得到了保證。

靜態資料初始化:

靜態資料只佔用一份儲存區域。靜態初始化只有在必要時候進行。只有在第一個型別物件建立(或第一次訪問靜態資料)的時候,他們才會被初始化。此後,靜態物件不會再被初始化。

初始化順序:

靜態物件(只一次)——> 非靜態物件——>構造器

可以使用靜態塊的方式,對靜態物件成員進行初始化,放在static關鍵字後面,如下:

public class Spoon {         static int i;         static {            i = 47;         }       }

非靜態例項初始化:

如上,看起來比靜態塊少了個static關鍵字,它保證了每新建一個該類的物件,不論呼叫何種構造器,這些操作都會發生。例項初始化子句是發生在構造器之前執行。

Mug mug1;         Mug mug2;         {           mug1 = new Mug(1);           mug2 = new Mug(2);           print("mug1 & mug2 initialized");         } 

8 陣列初始化

注意陣列的別名問題。

不確定在數組裡需要多少個元素時,可以直接new。在執行時再建立。這裡再提一下,陣列元素中基本資料型別,數字和字元會被自動初始化為0,而布林型會自動初始化為false。

Array.toString()方法屬於java.util標準類庫,它將產生一維陣列的可列印版本。

試圖使用陣列中的空引用(null),則會在執行時產生異常。

可變引數列表(C通常稱之為varags):

所謂可變引數列表,可以理解為函式的引數列表中某型別的數量是不確定的。這個特性是在JavaSE5之後新增的。

static void printArray(Object... args) {            for(Object obj : args)              System.out.print(obj + " ");            System.out.println();         } 

有了可變引數,就不用顯示的編寫陣列語法了,當指定引數,編譯器會自動填充陣列。也就是輸入一個列表,編譯器會自動將其轉化為陣列,作為可變引數列表接受。

0個引數傳遞給可變引數列表是可行的,當局有可選的尾隨引數時,這一特性就會很有用。

對於如下方法:

 static void f(int required, String... trailing) {            System.out.print("required: " + required + " ");            for(String s : trailing)              System.out.print(s + " ");            System.out.println();         } 

f(0)是可以代入的,儘管並沒有String型別引數。

getClass()方法屬於Object的一部分,它將產生物件的類,並且在列印該類時,可以看到該型別的編碼字串。前導[表示int型別。

它是這樣用的:

static void g(int... args) {            System.out.print(args.getClass());            System.out.println(" length " + args.length);         }

輸出是這樣的:

     class [Ljava.lang.Character; length 1       class [Ljava.lang.Character; length 0       class [I length 1       class [I length 0       int[]: class [I 

可以在單一的引數列表中將型別混合在一起,而自動包裝機制將有選擇的將Int提升為Integer。可變引數列表使過載變得複雜,編譯器無法知道應該呼叫哪種方法。因此應當總是隻在過載的一個版本上使用可變引數列表,或者壓根不用。

9 列舉型別

Java SE5添加了enum關鍵字

(列舉型別的例項都是常量,因此都用大寫字母表示,如果有多個單詞,就用下劃線隔開。)

建立一個列舉型別:

public enum Spiciness {         NOT, MILD, MEDIUM, HOT, FLAMING       }

建立enum例項:

Spiciness howHot = Spiciness.MEDIUM;

enum的一些特性:

toString() 函式可以方便的顯示某個例項的名字。

ordinal() 函式可以顯示某個特定enum常量的申明順序。

static values() 函式可以按照enum常量的申明順序構成相應陣列。

列舉型別可以配合switch case使用。