問題:在構造器里調用可重寫的方法有什么問題?
我有一個檢票頁面的類通過抽象方法的結果去去設置頁的標題
public abstract class BasicPage extends WebPage {public BasicPage() {add(new Label("title", getTitle()));}protected abstract String getTitle();}
NetBeans就警告我"Overridable method call in constructor"這個信息,但是這是什么錯誤鴨?
我能想到的唯一替代方案就將抽象方法的結果傳遞給子類的父類構造器,但是很多參數就無法讀取了
回答一
下面有一個幫助你理解的例子
public class Main {static abstract class A {abstract void foo();A() {System.out.println("Constructing A");foo();}}static class C extends A {C() { System.out.println("Constructing C");}void foo() { System.out.println("Using C"); }}public static void main(String[] args) {C c = new C(); }
}
如果你跑一下上面的代碼,就會得到下面的結果
Constructing A
Using C
Constructing C
看到了嗎?foo()
使用到了C,在C的構造函數開始跑之前。如果foo()
要求c有一個確定的狀態(構造函數已經完成了),那么就會遇到一個C未被定義的狀態,就會直接失敗了。因此你不能確定A里面可重寫的foo()
需要什么,你就會碰到一個警告了。
回答二
下面這個例子揭露了當在父類構造器中調用一個可重寫的方法可能出現的邏輯問題
class A {protected int minWeeklySalary;protected int maxWeeklySalary;protected static final int MIN = 1000;protected static final int MAX = 2000;public A() {setSalaryRange();}protected void setSalaryRange() {throw new RuntimeException("not implemented");}public void pr() {System.out.println("minWeeklySalary: " + minWeeklySalary);System.out.println("maxWeeklySalary: " + maxWeeklySalary);}
}class B extends A {private int factor = 1;public B(int _factor) {this.factor = _factor;}@Overrideprotected void setSalaryRange() {this.minWeeklySalary = MIN * this.factor;this.maxWeeklySalary = MAX * this.factor;}
}public static void main(String[] args) {B b = new B(2);b.pr();
}
結果可能是:
minWeeklySalary: 0maxWeeklySalary: 0
這是因為B的構造器第一次調用A的構造器,B里面可重寫的方法就會被執行。但是里面執行的方法需要使用到我們實例的變量,但是我們實例的變量還未被初始化(因為A的構造器還沒完成執行),因為這個變量的值0,而不是1也沒有被定義為2(程序員可能認為是這樣的)。如果這種邏輯推導要干十多次的話,那就很難去追蹤一個錯誤了
我希望這對你是有幫助的
文章翻譯自Stack Overflow:https://stackoverflow.com/questions/3404301/whats-wrong-with-overridable-method-calls-in-constructors