每日一題:考察子類重寫父類方法時,可變參數 int... nums 與陣列參數 int[] nums 在簽名層面的差異,導致編譯失敗。
class Parent {
public void sum(int num1, int... nums) {
System.out.println("Parent... sum");
}
}
class Sub extends Parent {
@Override
public void sum(int num1, int[] nums) {
System.out.println("Sub... sum");
}
}
public class Test {
public static void main(String[] args) {
Parent p = new Sub();
p.sum(1, 2);
Sub s = new Sub();
s.sum(1, 2);
}
}
答案:有編譯錯誤,錯誤發生在 Sub 類的 @Override 方法聲明處。
void sum(int num1, int... nums) → 編譯後簽名 (I[I)V (參數類型:int, int[])void sum(int num1, int[] nums) → 編譯後簽名 (I[I)V (參數類型:int, int[])兩個方法若擁有相同的方法名、類型參數、參數類型列表,但其中一個是可變參數方法而另一個不是,則它們不是重寫關係,而是重載關係。
因此 Sub.sum(int, int[]) 無法重寫Parent.sum(int, int...),編譯器報錯:
error: method does not override or implement a method from a supertype
@Override
public void sum(int num1, int[] nums) {
^
class Sub extends Parent {
// 無 @Override,視為重載
public void sum(int num1, int[] nums) { ... }
}
Parent p = new Sub(); p.sum(1,2); 調用父類可變參數版(輸出 Parent... sum)。Sub s = new Sub(); s.sum(1,2); 調用子類陣列版(輸出 Sub... sum)。int... nums。int[] nums,調用處顯式傳陣列 sum(1, new int[]{2})。// 正確重寫
class Sub extends Parent {
@Override
public void sum(int num1, int... nums) {
System.out.println("Sub... sum");
}
}
| 場景 | 結果 | 說明 |
|---|---|---|
父類 void m(int...),子類 void m(int[]) | 編譯錯誤 (加 @Override) | 簽名不匹配 |
父類 void m(int[]),子類 void m(int...) | 編譯錯誤 | 同上 |
同類內 void m(int...) + void m(int[]) | 編譯錯誤 | 重載簽名衝突 (擦除後相同) |
調用 m(1,2,3) 匹配哪個? | 優先匹配固定參數 | 若只有可變參數版則匹配它 |
可變參數不是陣列的語法糖,它在方法簽名中帶有 ACC_VARARGS 標記。重寫要求簽名完全一致(含可變參數標記),重載不允許擦除後簽名相同。記住鐵律:父類用可變參數,子類重寫必須也用可變參數;父類用陣列,子類重寫必須也用陣列。這道題精準考察對 Java 方法解析機制的深度理解。