繁体   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