現在讓我們用不同的眼光來看看本章的頭一個例子。在下面這個程序中,方法play()的接口會在被覆蓋的過程中發生變化。這意味著我們實際並沒有“覆蓋”方法,而是使其“過載”。編譯器允許我們對方法進行過載處理,使其不報告出錯。但這種行為可能並不是我們所希望的。下面是這個例子:
//: WindError.java // Accidentally changing the interface class NoteX { public static final int MIDDLE_C = 0, C_SHARP = 1, C_FLAT = 2; } class InstrumentX { public void play(int NoteX) { System.out.println("InstrumentX.play()"); } } class WindX extends InstrumentX { // OOPS! Changes the method interface: public void play(NoteX n) { System.out.println("WindX.play(NoteX n)"); } } public class WindError { public static void tune(InstrumentX i) { // ... i.play(NoteX.MIDDLE_C); } public static void main(String[] args) { WindX flute = new WindX(); tune(flute); // Not the desired behavior! } } ///:~
這裡還向大家引入了另一個易於混淆的概念。在InstrumentX中,play()方法采用了一個int(整數)數值,它的標識符是NoteX。也就是說,即使NoteX是一個類名,也可以把它作為一個標識符使用,編譯器不會報告出錯。但在WindX中,play()采用一個NoteX句柄,它有一個標識符n。即便我們使用“play(NoteX NoteX)”,編譯器也不會報告錯誤。這樣一來,看起來就象是程序員有意覆蓋play()的功能,但對方法的類型定義卻稍微有些不確切。然而,編譯器此時假定的是程序員有意進行“過載”,而非“覆蓋”。請仔細體會這兩個術語的區別。“過載”是指同一樣東西在不同的地方具有多種含義;而“覆蓋”是指它隨時隨地都只有一種含義,只是原先的含義完全被後來的含義取代了。請注意如果遵守標准的Java命名規范,自變量標識符就應該是noteX,這樣可把它與類名區分開。
在tune中,“InstrumentX i”會發出play()消息,同時將某個NoteX成員作為自變量使用(MIDDLE_C)。由於NoteX包含了int定義,過載的play()方法的int版本會得到調用。同時由於它尚未被“覆蓋”,所以會使用基礎類版本。
輸出是:
InstrumentX.play()