2011-08-05 42 views
1

檢查下面的代碼示例:方法重載和多態 - 什麼是更乾淨的方式來做到這一點?

public class Test 
{ 
    private void process(Instance1 obj) 
    { 
     System.out.println("Process Instance 1"); 
    } 

    private void process(Instance2 obj) 
    { 
     System.out.println("Process Instance 2"); 
    } 

    /* 
    COMMENT THIS OUT - I DON'T HAVE THIS CODE IN REAL LIST. Only here to prove point 3 below calls this 
    private void process(SuperClass obj) 
    { 
     System.out.println("Process superclass"); 
    } 
    */ 

    /** 
    * @param args 
    */ 
    public static void main(String[] args) 
    { 
     Test test = new Test(); 
     Instance1 instance1 = test.new Instance1(); 
     Instance2 instance2 = test.new Instance2(); 
     SuperClass instance3 = test.new Instance1(); 

     // test #1   
     test.process(instance1); 
     // test #2   
     test.process(instance2); 
     // test #3 (compiler error unless there is a process(SuperClass obj) call) 
     test.process(instance3); 
     // test #4      
     if(instance3 instanceof Instance1) 
      test.process((Instance1)instance3); 
     else if(instance3 instanceof Instance2) 
      test.process((Instance2)instance3); 

    } 

    abstract class SuperClass 
    { 
    } 

    class Instance1 extends SuperClass 
    { 
    } 

    class Instance2 extends SuperClass 
    { 
    } 
} 

這使輸出:

Process Instance 1 
Process Instance 2 
Process superclass 
Process Instance 1 

我希望測試#3會知道調用合適的功能,但它似乎沒有。我想這是編譯時的事情,而不是運行時的事情。選項#4有效,但很醜,我希望有更好的方法。

更新:澄清問題...我有一個抽象類,其中存在兩個具體實現。我想要的是在另一個類中有兩個重載方法(每個具體類都有一個),並且能夠在不做任何醜事的情況下調用它。從我現在知道的情況來看,這是不可能的,因爲這是一個編譯時問題,編譯器顯然不知道它是什麼具體類時,它不是強類型。

+0

搜索「雙重分派」。 – Artefacto

回答

3

這不是多態性問題。這是方法重載的問題。

當你傳遞instance3process(),它會調用process(SuperClass obj)因爲只要JVM是知道的,instance3SuperClass,因爲這就是你宣佈它作爲。

如果你想所需的行爲(試驗#3打印出 「過程實例1」),你應該定義你的process()方法,像這樣:

private void process(SuperClass obj) 
{ 
    System.out.println("Process " + obj.name()); 
} 

而且你的類是這樣的:

abstract class SuperClass 
{ 
    String name() { 
     return "SuperClass"; 
    } 
} 

class Instance1 extends SuperClass 
{ 
    String name() { 
     return "Instance 1"; 
    } 
} 

class Instance2 extends SuperClass 
{ 
    String name() { 
     return "Instance 2"; 
    } 
} 

這將因動態(或遲到)方法綁定而起作用。

+0

我並沒有真正遵循這個解決方案。我需要的是正確的process()函數被調用。演示中正在打印的內容與此無關。我試圖找到比使用instanceof操作符更好的解決方案。 –

0

要麼使其層次內的虛函數:

abstract class SuperClass 
{ 
    public void process() { System.out.println("Process super class"); } 
} 

class Instance1 extends SuperClass 
{ 
    public void process() { System.out.println("Process instance1"); } 
} 

class Instance2 extends SuperClass 
{ 
    public void process() { System.out.println("Process instance2"); } 
} 

或退房various approaches到未在本機支持Java多分派。

+0

process()調用將SuperClass(或子類)作爲參數。它不是SuperClass的一部分 –

0

更清潔的方式夫婦建議做你正在做的事情:

選項1:抽象方法Superclass定義process(),並覆蓋其上Instance1Instance2

abstract class SuperClass 
{ 
    public void process(String[] args) 
    { 
     System.out.println("Process superclass"); 
    } 
} 

class Instance1 extends SuperClass 
{ 
    @Override 
    public void process(String[] args) 
    { 
     System.out.println("Process Instance 1"); 
    } 
} 

class Instance2 extends SuperClass 
{ 
    @Override 
    public void process(String[] args) 
    { 
     System.out.println("Process Instance 2"); 
    } 
} 

選項2:訪問者模式 定義執行處理的類,並且是InstanceVisitor

public interface InstanceVisitor 
{ 

    public void processSuperclass(Superclass obj, String[] args); 

    public void processInstance1(Instance1 obj, String[] args); 

    public void processInstance2(Instance2 obj, String[] args); 

} 

public class InstanceProcessor implements InstanceVisitor 
{ 

    public void processSuperclass(Superclass obj, String[] args) 
    { 
     System.out.println("Process superclass"); 
    } 

    public void processInstance1(Instance1 obj, String[] args) 
    { 
     System.out.println("Process Instance 1"); 
    } 

    public void processInstance2(Instance2 obj, String[] args) 
    { 
     System.out.println("Process Instance 2"); 
    } 

} 

然後每個子類接受訪問者,並調用正確的方法:

abstract class SuperClass 
{ 
    public void accept(InstanceVisitor v, String[] args) 
    { 
     v.visitSuperclass(this, args); 
    } 
} 

class Instance1 extends SuperClass 
{ 
    @Override 
    public void accept(InstanceVisitor v, String[] args) 
    { 
     v.visitInstance1(this, args); 
    } 
} 

class Instance2 extends SuperClass 
{ 
    @Override 
    public void accept(InstanceVisitor v, String[] args) 
    { 
     v.visitInstance2(this, args); 
    } 
} 
+0

我對以前的帖子有類似的評論。 process()函數將SuperClass的一個實例作爲參數。它內部沒有process()函數。我將澄清最初的問題 –

0

你能不能改SuperClassInstance S'如果是這樣,你應該聲明抽象方法SuperClass.process()並在子類中實現它。

爲了測試#3的工作,你可以添加鑄造:test.process((Instance1)instance3);。醜陋。

你也可以定義一個工廠類,並封裝在它裏面型開關。 你必須ProcessFactoryProcessObject getInstance(SuperClass obj)方法返回ProcessObjectInstance1類型或ProcessObjectInstance2的對象,有方法process()ProcessFactory將與您的測試#4類似。

0

這是我目前在做什麼。基本上把問題翻了一番。不確定這是否作爲訪問者模式。

基本上我只是增加了一個executeProcessor(測試試驗)內父類的抽象函數,具體的類隱含知道調用哪個函數,使他們能夠簡單地用一個演員。

您認爲如何?這個代碼是否有味道?或者一個整潔的解決方案?

public class Test 
{ 
    private void process(Instance1 obj) 
    { 
     System.out.println("Process Instance 1"); 
    } 

    private void process(Instance2 obj) 
    { 
     System.out.println("Process Instance 2"); 
    } 

    /** 
    * @param args 
    */ 
    public static void main(String[] args) 
    { 
     Test test = new Test(); 

     // Test 1 
     Instance1 instance1 = test.new Instance1(); 
     instance1.executeProcessor(test); 

     // Test 2 
     Instance2 instance2 = test.new Instance2(); 
     instance2.executeProcessor(test); 

     // Test 3 (note this is not strongly typed) 
     SuperClass instance3 = test.new Instance1(); 
     instance3.executeProcessor(test); 
    } 

    abstract class SuperClass 
    { 
     public abstract void executeProcessor(Test test); 
    } 

    class Instance1 extends SuperClass 
    { 

     @Override 
     public void executeProcessor(Test test) 
     { 
      test.process((Instance1)this); 
     } 
    } 

    class Instance2 extends SuperClass 
    { 

     @Override 
     public void executeProcessor(Test test) 
     { 
      test.process((Instance2)this); 
     } 
    } 
} 
0

正如其他人指出的那樣,這在Java中並不是真的。如果你絕對必須,你可以使用反射像做:

private void process(SuperClass obj) 
{ 
    try 
    { 
    Class<? extends SuperClass> klass = obj.getClass(); 
    Method m = this.getClass().getMethod("process", klass); 
    m.invoke(this, obj); 
    } 
    catch (Exception e) 
    { 
    // default behavior 
    System.out.println("Process superclass"); 
    } 
} 

我真的遵循的其他建議一個但是。

相關問題