2013-06-30 59 views
2

我對Java相對較新,希望對以下查詢有所幫助。我定義了兩個類 - 爲了簡單起見,我們稱它們爲ABClass A具有名爲methodA的方法,並且Class B具有名爲methodB的方法。這兩個類的對象包含在一個叫做containerArrayList中。我需要做的是循環訪問ArrayList並根據對象的類型調用不同的方法。迭代Java ArrayList並根據類別執行不同的方法

這是目前我的代碼:

for (Object item : container) { 
    if (item instanceof A) { 
     item.methodA() 
    } else if (item instanceof B) { 
     item.methodB() 
    } 
} 

我的IDE(NetBeans的)將不會編譯上面的代碼,因爲Object類型的item沒有methodAmethodB。有沒有其他的方式來編寫循環來完成我需要它做的事情?謝謝。

+0

爲什麼在if和else內容後沒有添加分號? – PVR

+1

你應該閱讀關於多態性 – thriqon

回答

5

您需要添加演員。僅僅因爲您檢查了該項目是A(或B)的一個實例,不允許您在該項目上調用方法。

if (item instanceof A) { 
    ((A) item).methodA(); 
} else if (item instanceof B) { 
    ((B) item).methodB(); 
} 

一般來說,您可能需要考慮重構您的代碼以避免此模式。例如,可以創建基類的通用接口,其中A和B兩者實施:

public interface MyInterface { 
    void doSomething(); 
} 

class A : MyInterface { 
    ... 
    public void doSomething() { this.methodA(); } 
} 


class B : MyInterface { 
    ... 
    public void doSomething() { this.methodB(); } 
} 

然後,你可以做:

List<MyInterface> list = // a list of A's and B's 
for (MyInterface item : list) { 
    // use polymorphism to invoke the appropriate method 
    item.doSomething(); 
} 

visitor pattern爲這種類型的代碼另一種常見的解決方案,它當您想要在固定的一組類中支持一些不同的常見操作而不經常修改這些類時,它非常有用。

0

只是做類型轉換爲A或B,呼籲it.Convert項目方法分爲A或B之前調用該方法

for (Object item : container) { 
    if (item instanceof A) { 
     ((A) item).methodA();; 
    } else if (item instanceof B) { 
     ((B) item).methodB(); 
    } 
} 
+0

在技術上是正確的,但最好的答案是多態性。應該有一個通用的方法,這兩個類的實現方式不同。 – Dan

0

嘗試以這種方式

 if (item instanceof A) { 
      ((A) item).methodA(); 
     } else if (item instanceof B) { 
      ((B) item).methodB(); 
     } 
2

你正在處理前變體問題,對於這個問題,Java(以及幾乎任何其他廣泛使用的語言)都沒有好的答案。 Scala通過案例類解決了這個問題,像ML這樣的學術語言可以輕鬆處理。

以上所有答案都建議使用if-ladders和casting,這是Java中最早的解決方案,但基本上放棄了編譯時安全性。如果您不喜歡演員陣容,可以使用訪問者模式來解決問題。它儘可能詳細,但它是完全類型安全的。

interface ABVariantVisitor { 
    void visit(A a); 
    void visit(B b); 
} 

interface ABVariant { 
    void accept(ABVariantVisitor v); 
} 

class A implements ABVariant { 
    // ... 
    void accept(ABVariantVisitor v) { 
     v.visit(this); 
    } 
    // ... 
} 

class B implements ABVariant { 
    // ... 
    void accept(ABVariantVisitor v) { 
     v.visit(this); 
    } 
    // ... 
} 

List<ABVariant> container; 

// ... 

for (ABVariant item : container) { 
    item.accept(new ABVariantVisitor() { 
     @Override void visit(A a) { 
      a.methodA(); 
     } 
     @Override void visit(B b) { 
      b.methodB(); 
     } 
    }); 
} 
+0

在我看來,這是最好的解決方案。它非常OO,乾淨,不會干擾課程的原始設計和實施。 ChaseMedallion的答案很好,但它需要改變原始類的實現,並將行爲與一個類聯繫起來,該類本來不應該具有這種行爲。 唯一沒有得到的是爲什麼在每次迭代中生成一個新的ABVariationVisitor。這可以提取到循環的外部。 – Avi

+0

匿名類實際上並不是最有效的實現,但是我這樣寫它以使新代碼看起來儘可能接近舊代碼。訪客最大的問題之一是閱讀起來很難,尤其是當你按照你的建議進行考慮時。 –