簡體   English   中英

Java Generics方法參數傳遞問題

[英]Java Generics method parameter passing issue

我有一個關於將參數傳遞給泛型方法的問題。 代碼如下:

public class View<T extends View<T,PM>, PM extends Source>  {

    protected PM source;
    protected EventManager<T, PM> eventManager;

    public View(PM s){
        this.source = s;
        eventManager = new EventManager<T, PM>();
        eventManager.setTarget(this); //error: "The method setTarget(T) in the type
                              //EventManager<T,PM> is not applicable for the arguments (View<T,PM>)"

        eventManager.setSource(s);
    }

    public void setBinding(Topic topic, IEventAction<T,PM> action){
        eventManager.setEventAction(topic, action)
    }

}

/** 
* EventManager class has to remain completely generic. The type parameters cannot "extends"
* anything because the EventManager is used also in other parts where T and S will have to be
* classes other than "View" and "Source"
*/
public class EventManager<T, S> {
    protected T target;
    protected S source;
    private LinkedHashMap<Topic, IEventAction<T, S>> eventActions;

    public EventManager(T target, S source){
        this.target = target;
        this.source = source;
    }

    public void setTarget(T target){
        this.target = target;
    }

    public void setSource(S source){
        this.source = source;
    }

    public void setEventAction(Topic topic, IEventAction<T, S> action) {
        //some code here ...
        omissis...

        eventActions.put(topic, action);

        omissis...
    }

    //other methods down here...omissis
}

Eclipse給出了我在“eventManager.setTarget(this);”行中發表評論的錯誤。 我不明白為什么它給了我這個錯誤。 無論如何,我找到了一個解決方案(顯然),但我不確定我是否做了“干凈”或“骯臟”的事情。 解決方案是這樣的:

 eventManager.setTarget((T)this);

但它給了我一個警告:“類型安全:未經檢查從視圖轉換為T”。 為了消除警告,我還在構造函數方法的頂部放置了以下內容:

@SuppressWarnings("unchecked")

它似乎有效,但有什么不對? 你有另一個“更清潔”的解決方案(如果存在)? 你認為這是一種“骯臟”的方法嗎?

任何soggestions非常歡迎。

發生錯誤是因為您使用T實例化EventManager,它可以是運行時View的任何子類,但您正在傳遞完全View(在編譯時已知)。 因為通常在需要子類時不能傳遞超類,所以代碼不能編譯。

解決方案(不更改代碼)當然是將超類強制轉換為子類(這就是你正在做的事情),並盡量不要獲得ClassCastException。

如果你確定你永遠不會傳遞不兼容的類型,那么我猜(雖然很混亂)。 也許試着以某種方式重新設計它。

在線

public class View<T extends View<T,PM>, PM extends Source>  {

你似乎想T是“的類型this ”。 但這並沒有用語言表達。

通常,這里的方法是使類抽象並添加一個抽象的getThis方法:

public abstract class View<THIS extends View<THIS,PM>, PM extends Source>  {
    protected abstract THIS getThis();
    ...
        eventManager.setTarget(getThis());
        ...

public final class SomeView extends View<SomeView,SomeSource> {
    protected SomeView getThis() {
        return this;
    }
    ...

錯誤是因為事件管理器在構造期間被初始化為保持一種“T”類型,但是您正在嘗試分配一個“View”實例(T擴展View,使View成為超類),這是不對的。

我同意Tudor的說法,但最好的做法是不要為方法/構造函數抑制未經檢查的警告。 這將導致隱藏任何其他未經檢查的異常。 我建議你做你需要的線路。 以下是示例。

@SuppressWarnings("unchecked")
T t = (T)this;
eventManager.setTarget(t);

我認為遵守聲明EventManager應該擴展View,因為T on line eventManager = new EventManager<T, PM>(); 被定義為T extends View<T,PM> - 命名類型模板同樣令人困惑。

我不知道你在做什么,但這里有些東西。

解決方案1

public class View<PM extends Source>  {

    protected PM source;
    protected EventManager<View<PM>, PM> eventManager;

    public View(PM s){
        this.source = s;
        eventManager = new EventManager<>(); // diamond notation (Java 7 only)
        eventManager.setTarget(this); 
        eventManager.setSource(s);
    }
}    

您仍然可以擁有View子類,並且setTarget始終會收到正確的預期類型。

解決方案2:

EventManager應該只將Source (或子類)作為源,不是嗎?

public class View {

    protected Source source;
    protected EventManager<View> eventManager;

    public View(Source s){
        this.source = s;
        eventManager = new EventManager<>(); // diamond notation (Java 7 only)
        eventManager.setTarget(this); 
        eventManager.setSource(s);
    }
}    

public class EventManager<T> {
   protected T target;
   protected Source source;

   public void setTarget(T t) ...
   public void setSource(Source s) ...
}

解決方案3

您應該有一個Target類或接口,這樣EventManager就不會被參數化, View會擴展或實現Target 你根本就沒有任何泛型。 如果簡單的繼承可以完成這項工作,那么就不需要泛型。

注意 :正如Scorpion所提到的,你不應該在構造函數中逃避this ; 您可能會獲得一些事件,在完全構建之前觸發對View的訪問。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM