2016-09-15 120 views
0

比方說,你有實現該接口的接口和兩個類:Java - 在編譯時如何在不知道結果類型的情況下返回變量類型對象?

public interface IElement { 
    boolean isDisplayed(); 
} 

public class Button implements IElement { 
    @Override 
    public boolean isDisplayed() { 
     // checks if displayed 
     return false; 
    } 

    public void click() { 
     // clicks 
    } 
} 

public class Textbox implements IElement { 
    @Override 
    public boolean isDisplayed() { 
     // checks if displayed 
     return false; 
    } 

    public void enterText(String text) { 
     // enters text 
    } 
} 

而且在一個完全獨立的類我們有希望返回一個按鈕或根據所提供的值的文本框的方法參數。東西是這樣的:

public class WhichElement { 

    public <T extends IElement> T getElement(String elementName) { 

     if (elementName.equalsIgnoreCase("button")) { 
      return new Button(); 
     } 
     else if (elementName.equalsIgnoreCase("textbox")) { 
      return new Textbox(); 
     } 
    } 
} 

但是失敗了,因爲返回的對象不是類型T. 我試着剛返回界面如下:

public IElement getElement(String elementName) 

但我不能做我真正想做的事情,這是這樣的:

WhichElement picker = new WhichElement(); 
picker.getElement("button").click(); <-- errors here because it's an IElement not a Button :(

我可以將它轉換爲正確的對象和信任,返回相同的一個,因爲我將它轉換爲方法......但似乎危險。我更願意確定所需對象的類型並直接返回該對象。 有沒有辦法做我想做的事?

+0

你不能這樣做,因爲編譯器不知道將''按鈕''傳遞給'getElement'會導致'Button'被返回。如果你可以保證它是一個'Button',就投它。 –

+0

使用泛型時,如果返回'IElement',編譯器會在需要進行強制轉換的地方插入一個強制轉換。如果你不能保證類型是正確的,你認爲編譯器可以如何? – erickson

+0

我建議將參數從String改爲'Class clazz',然後做'clazz.newInstance()'。 – Shadov

回答

3

您可以在返回之前將getElement()的結果轉換爲T,這會產生編譯器警告。

由於編譯器要在調用站點插入強制轉換,並且運行時結果不是正確的類型,因此會從沒有明顯強制轉換的位置引發ClassCastException。實質上,如果getElement()不是通用的,編譯器會生成相同的代碼,並且僅返回IElement

不是用一種工廠方法來生成多種類型,而是爲每種類型創建不同的工廠方法。這將爲您提供類型安全性,確保應用程序需要的每個元素都實際提供,幫助重構,並將運行時錯誤(如getElement("buttton"))更改爲編譯時錯誤。

依賴注入是另一種方法:給應用程序一個按鈕,而不是定位一個本身。

+0

對T的投射將需要在getElement()內發生。即便如此,他也無法以他想要的方式調用click()。儘管如此,我還是應該使用替代方法。 – Zachary

+0

@Zachary是的,這就是我的意思,但不清楚,是嗎?我會解決這個問題。 – erickson

0

有兩種方法。

public Button getButton() { 
    return new Button(); 
} 

public Textbox getTextbox() { 
    return new Textbox(); 
} 

這裏沒有太大的區別,語義和codewise

picker.getButton()   // Strongly typed 
picker.getElement("button") // Stringly typed 

加上stringly typed版本更長。

相關問題