有效的構(gòu)造函數(shù)調(diào)用 首先,為了對類型參數(shù)構(gòu)造合法的 new 表達(dá)式(如 new T()),必須確保我們調(diào)用的構(gòu)造函數(shù)對于 T 的每個實例化都有效。但由于我們只知道 T 是其已聲明界限的子類型,所以我們不知道 T 的某一實例化將有什么構(gòu)造函數(shù)。要解決這一問題,可以用下述三種方法之一:
class D< S> { C< S> makeC() { return new C< S>(); } }
現(xiàn)在,在類 D< S> 中,構(gòu)造了類 C< S> 的實例。然后,在類 C 的主體中,將調(diào)用 S 的不帶參數(shù)的構(gòu)造函數(shù)。這種不帶參數(shù)的構(gòu)造函數(shù)存在嗎?答案當(dāng)然取決于 S 的實例化!
比方說,假如 S 被實例化為 String,那么答案是“存在”。假如它被實例化為 Integer,那么答案是“不存在”。但是,當(dāng)編譯類 D 和 C 時,我們不知道其它類會構(gòu)造什么樣的 D< S> 實例化。即使我們有可用于分析的整個程序(我們幾乎從來沒有這樣的 Java 程序),我們還是必須進(jìn)行代價相當(dāng)高的流分析來確定潛在的構(gòu)造函數(shù)問題可能會出現(xiàn)在哪里。
此外,這一技術(shù)所產(chǎn)生的錯誤種類對于程序員來說很難診斷和修復(fù)。例如,假設(shè)程序員只熟悉類 D 的頭。他知道 D 的類型參數(shù)的界限是缺省界限(Object)。假如得到那樣的信息,他沒有理由相信滿足聲明類型界限(如 D< Integer>)的 D 的實例化將會導(dǎo)致錯誤。事實上,它在相當(dāng)長的時間里都不會引起錯誤,直到最后有人調(diào)用方法 makeC 以及(最終)對 C 的實例化調(diào)用方法 makeT。然后,我們將得到一個報告的錯誤,但這將在實際問題發(fā)生很久以后 — 類 D 的糟糕實例化。
還有,對所報告錯誤的堆棧跟蹤甚至可能不包括任何對這個糟糕的 D 實例的方法調(diào)用!現(xiàn)在,讓我們假設(shè)程序員無權(quán)訪問類 C 的源代碼。他對問題是什么或如何修正代碼將毫無頭緒,除非他設(shè)法聯(lián)系類 C 的維護(hù)者并獲得線索。
在上面的代碼中,我們在哪里報告錯誤呢?在類 D 的編譯過程中還是在包含不相干表達(dá)式 new D< C< Object>>().nest(1000) 的客戶機(jī)類的編譯過程中呢?無論是哪一種,除非程序員有權(quán)訪問類 C 的源代碼,否則他無法預(yù)知何時會發(fā)生編譯錯誤。