不要強制轉換這個類!
與可怕的 null 指標異常(該異常除了報告null 指標之外,對於將要發生的事情什麼也不說)不同,類強制轉換異常相對來說容易調試。
類強制轉換經常發生在遞迴下行資料結構的程式中,通常是當代碼的某些部分在每次方法調用中下行了兩級且在第二次下行時調度不當時發生的。程式員可通過學習 Double Descent 錯誤模式來識別這種問題。
Double Descent 錯誤模式
本周的專題是 Double Descent 錯誤模式。它通過類強制轉換異常來表明。它是由遞迴下行複合資料結構引起的,這種下行方式有時在一次遞迴調用中要下行多級。這樣做經常需要添加類型強制轉換來編譯代碼。但是,在這種下行中,很容易忘記檢查是否滿足了適當的不變數來保證這些類型強制轉換成功。
考慮以下的 int 二元樹的類階層。因為我們希望考慮到空樹的情況,所以將不把 value 欄位放入 Leaf 類中。由於這一決定使所有的 Leaf 相同,我們將用一個靜態欄位為 Leaf 保留一個單元素。
清單 1. int 二元樹的類階層
abstract class Tree {
}
class Leaf extends Tree {
public static final Leaf ONLY = new Leaf();
}
class Branch extends Tree {
public int value;
public Tree left;
public Tree right;
public Branch(int _value, Tree _left, Tree _right) {
this.value = _value;
this.left = _left;
this.right = _right;
}
}
現在,假定我們希望在 Tree 上添加一個方法,該方法確定任意兩個連貫的節點(比如一個分支和它的其中一個子分支)是否都包含一個 0 作為它們的值。我們可能添加以下方法(注意:最後一個方法將不以它的當前形式編譯):
清單 2. 確定兩個連貫的節點是否都包含值 0 的方法
// in class Tree:
public abstract boolean hasConsecutiveZeros();
// in class Leaf:
public boolean hasConsecutiveZeros() {
return false;
}
// in class Branch:
public boolean hasConsecutiveZeros() {
boolean foundOnLeft = false;
boolean foundOnRight = false;
if (this.value == 0) {
foundOnLeft = this.left.value == 0;
foundOnRight = this.right.value == 0;
}
if (foundOnLeft || foundOnRight) {
return true;
}
else {
foundOnLeft = this.left.hasConsecutiveZeros();
foundOnRight = this.right.hasConsecutiveZeros();
return foundOnLeft || foundOnRight;
}
}