2016-03-02 38 views
0

鑑於此代碼:的Java多態性/重載驚喜

class Task{}; 
class TaskA extends Task{}; 

class TopWorker{ 
    //... omitting constructor, instance variables, etc. 
    public void work(Task task){ 
    this.subWorkerA.work(task) 
    //followed by more subworkers... 
    } 
} 

class SubWorkerA{ 
    public void work(TaskA task){ 
    // Subworker A does something interesting here 
    } 
    public void work(Task task){ 
    // Subworker A doesn't care, do nothing 
    } 
} 

TaskA task = new TaskA(); 
(new TopWorker).work(task); 

我期望爲work()TaskA簽名會,而不是called-,該Task版本被調用。我認爲問題是TopWorker只接受Task,所以java必須相應地調度SubWorker.work()

有沒有辦法解決這個問題?假設我有很多Tasks和許多工人,並且TopWorker在那裏以協調他們的結果。

+3

的方法過載被選擇在編譯時。所有編譯器都知道'task'是一個'Task',所以它知道它可以安全調用的唯一方法是'work(Task)'。 –

回答

1

之所以TaskA簽名不被稱爲是因爲TopWorker.work只能保證一個Task在不被傳遞一個TaskA實例。 SubWorkerA.work(Task task)最終會被調用,因爲它是唯一的參數爲Taskwork方法。如果您改爲撥打this.subWorkerA.work((TaskA)task),則會調用所需的方法,儘管這種方法本質上是不安全的。

我認爲你可能會用晚期綁定混淆方法重載。重載只是允許您以相同的方式命名方法,只要它們具有不同數量的參數或參數類型即可。當您調用重載方法時,將根據參數的構成選擇正確的方法。在後期綁定中,通過在子類中複製其簽名來重寫方法,即使將其父對象稱爲超類的實例,也會強制重寫方法被調用。

+0

感謝您指出後期綁定與重載;這絕對是我犯的認知錯誤。 –

+0

當然 - 很多人犯了這個錯誤,我自己包括:) – CodeBlind

0

我認爲Task將更好地是一個接口,在運行時可以計算出

public void work(Task task){ 

    if (task instanceof TaskA) 
     this.subWorkerA.work((TaskA) task); 
    } 
1

這裏是一個解決辦法...

public void work(Task task){ 
    if (task instanceof TaskA) { 
     work((TaskA) task); 
    } 
    // Subworker A doesn't care, do nothing 
} 
+0

感謝您的解決方法。 –