1. 程式人生 > >Java核心技術 卷I 基礎知識 學習筆記(4)

Java核心技術 卷I 基礎知識 學習筆記(4)

參考:Java核心技術 卷I 基礎知識

一個物件變數可以指示多種實際型別的現象被稱為多型。在執行時能夠自動地選擇呼叫哪個方法的現象被稱為動態繫結。

由一個公共超類派生出來的所有類集合被稱為繼承層次。在繼承層次中,通過某個特定類到其祖先的路徑被稱為該類的繼承鏈。

假設要呼叫x.f(args),隱式引數x宣告為類C的一個物件。下面是呼叫過程的詳細描述:

(1)編譯器檢視物件的宣告型別和方法名。假設呼叫x.f(param),且隱式引數x宣告為C類的物件。需要注意的是,有可能存在多個名字為f,但引數型別不一樣的方法。例如:可能存在方法f(int)和方法f(String)。編譯器將會一一列舉所有C類中名為f的方法和其超類中訪問屬性為public且名為f的方法(超類的私有方法不可訪問)。

至此,編譯器以獲得所有可能被呼叫的候選方法。

(2)接下來,編譯器將檢視呼叫方法時提供的引數型別。如果在所有的名為f的方法中存在一個與提供的引數型別完全匹配,就選擇這個方法。這個過程被稱為過載解析。例如:對於呼叫x.f("Hello")來說,編譯器將會挑選f(String),而不是f(int)。由於允許型別轉換,所以這個過程可能很複雜。如果編譯器沒有找到與引數型別匹配的方法,或者發現經過型別轉換後有多個方法與之匹配,就會報告一個錯誤。

至此,編譯器已經獲得需要呼叫的方法名字和引數型別。

(3)如果是private、static、final方法或者構造器,那麼編譯器可以準確地知道應該呼叫哪個方法,將這種呼叫方式稱為靜態繫結。與此對應的是,呼叫的方法依賴於隱式引數的實際型別,並且在執行時實現動態繫結。

(4)當程式執行,並且採用動態繫結呼叫方法時,虛擬機器已定呼叫與x所引用物件的實際型別最合適的那個類的方法。假設x的實際型別是D,它是C的子類。如果D類定義了方法f(String),就直接呼叫它,否則將在D類的超類中尋找f(String),以此類推。

動態繫結有一個非常重要的特定:無需對現存的程式碼進行修改,就可以對程式進行擴充套件。

阻止繼承:使用final類和方法

final類中的所有方法自動成為final方法、但是其中的域不會。

將方法或類宣告為final的主要目的是:確保它們不會再子類中改變語義。

如果一個方法沒有被覆蓋並且很短,編譯器就能夠對它進行優化處理,這個過程稱為內聯。

虛擬機器中的即使編譯器比傳統編譯器的處理能力強得多。這種編譯器可以準確地知道類之間的繼承關係,並能夠檢測出類中是否真正地存在覆蓋給定的方法。如果方法很簡短、被頻繁呼叫且沒有真正地被覆蓋,那麼即時編譯器就會將這個方法進行內聯處理。如果虛擬機器載入了另外一個子類,而在這個子類中包含了對內聯方法的覆蓋,那麼優化器將取消對覆蓋方法的內聯。

抽象方法充當著佔位的角色,它們的具體實現在子類中。擴充套件抽象類可以有兩種選擇。一種是在抽象類中定義部分抽象類方法或不定義抽象類方法,這樣就必須將子類也標記為抽象類,另一種是定義全部的抽象方法,這樣一來,子類就不是抽象的了。

類即使不包含抽象方法,也可以將類宣告為抽象類。

抽象類不能被例項化。

需要注意的是,可以定義一個抽象類的物件變數,但是它只能引用非抽象子類的物件。

在子類中定義equals方法時,首先呼叫超類的equals。如果檢測失敗,物件就不可能相等,如果超類中的域都相等,就需要比較子類中的例項域。

下面給出編寫一個完美的equals方法的建議:

(1)顯式引數命名為otherObject,稍後需要將它轉換成另一個叫做other的變數。

(2)檢測this與otherObject是否引用同一個物件

if(this==otherObject) return true;

這條語句只是一個優化,實際上,這是一種經常採用的形式。因為計算這個等式要比一個一個比較類中的所有域所付出的代價小的多。

(3)檢測otherObject是否為null,如果為null,返回false。這項檢測時很必要的。

if(otherObject==null) return false;

(4)比較this和otherObject是否屬於同一個類,如果equals的語義在每個子類中有所改動,就使用getClass檢測:

if(getClass()!=otherObject.getClass()) return false;

如果所有子類都有統一的語義,就是用instanceof檢測:

if(!(otherObject instanceof ClassName)) return false;

(5)將otherObject轉換為相應的類型別變數:

ClassName other=(ClassName) ohterObject;

(6)對所有需要比較的域進行比較了。使用==比較基本型別域,使用equals比較物件域。如果所有的域都匹配,就返回true,否則返回true。

如果在子類中重新定義equals,就要在其中包含呼叫super.equals(other)。

ArrayList是一個採用型別引數的泛型類。

裝箱和拆箱是編譯器認可的,而不是虛擬機器。編譯器在生成類的位元組碼時,插入必要的方法呼叫。虛擬機器只是執行這些位元組碼。

引數數量可變的方法,如:

public static double max(double... values){
    double largets=Double.NEGATIVE_INFINITY;
    for(double v: values) if(v>largest) largest=v;
    return largest;
}