我可以使用Java中的自绑定泛型和子类来避免这种未经检查的强制转换吗?

时间:2014-11-07 12:26:17

标签: java generics

我知道SO中有很多类似的问题,但我恐怕找不到我的模拟案例。如果有的话请原谅我(我希望链接:)。

我有这两个基类,带有自我限制的泛型:

public interface View<V extends View<V, P>, P extends Presenter<V, P>> {
    P getPresenter();
}

public abstract class Presenter<V extends View<V, P>, P extends Presenter<V, P>> {
    protected V view;

    public void takeView(V view) { this.view = view; }
}

这背后的原因是每个演示者都知道其视图的确切类别,反之亦然,因此他们可以互相交流调用方法而不用大惊小怪。 (每个演示者都会定义自己的视图来实现,因此架构更清晰,但你知道我的意思......)

如果我实施它们,就没有问题:

public class FooView implements View<FooView, FooPresenter> {
    @Override
    public FooPresenter getPresenter() {
        FooPresenter p = new FooPresenter();
        p.takeView(this); // Nice and clean!
        return p;
    }
}

public class FooPresenter extends Presenter<FooView, FooPresenter> {}

然后,我想为某种视图创建一个抽象基类:

public abstract class BaseView<V extends BaseView<V,P>, P extends Presenter<V,P>> extends SomeOtherBaseClass implements View<V, P>

但是我需要在链接演示者和视图时进行未经检查的演员表!

    @Override
    public P getPresenter() {
        P p = createPresenter(); // Another abstract, so every view can have its own presenter
        p.takeView((V) this); // Doesn't compile without casting, the cast is marked as unchecked
        return p;
    }

有趣的是,如果我不在BaseView中调用takeView,并在每个具体实现中执行它,它会再次工作......

public class BarView implements BaseView<BarView, FooPresenter> {
    @Override
    public FooPresenter getPresenter() {
        FooPresenter p = createPresenter();
        p.takeView(this); // javac likes this :/
        return p;
    }
}

有没有办法避免未经检查的演员?我认为Java泛型是一个限制,但我可能是有限的。 :d

非常感谢。

2 个答案:

答案 0 :(得分:2)

  

有没有办法避免未经检查的演员?

不,因为演员阵容不安全。

考虑以下内容,它满足界限:

class FooView extends BaseView<FooView, FooPresenter>
class BarView extends BaseView<FooView, FooPresenter>

然后在getPresenter()上致电BarView(V)this强制转换会将thisBarView)投射到VFooView),这是无效的演员。

  

另外,如果我不在BaseView中调用takeView,那么请执行此操作   每一个具体的实施,它再次有效......

如果您将声明更改为以下(有效),则不会:

class BarView implements BaseView<FooView, FooPresenter>

然后编译器会抱怨传递this


您可以通过向BaseView添加抽象方法来获取类型V的值来避免强制转换并使其安全:

abstract public V getView();

每个实施都必须实现这一点;对于V本身的类,例如FooView,然后可以return this;使用此功能

class FooView extends BaseView<FooView, FooPresenter> {
    public FooView getView() { return this; }
}

然后你可以在BaseView.getPresenter()中使用它,而不需要在每个子类中实现它:

public P getPresenter() {
    P p = createPresenter();
    p.takeView(getView());
    return p;
}

答案 1 :(得分:0)

这会将你的课程强烈地绑在一起,从它看来只能做双重调度。我认为你正在触及泛型可以做的事情的界限,但你可以以不同的方式实现同​​样的目标。

这不是对你的问题的直接回答,而是一种可能的替代方法:

public static abstract class Presenter<V extends View> implements ViewTaker<V> {
    protected V view;

    public void takeView(V view) { this.view = view; }
}

public interface View { // can be a class as well
}

public interface ViewTaker <V extends View> {
    public void takeView(V view);
}

在第二次阅读您的代码时,您可以创建该视图的演示者。这可能是伪代码的限制,但这对我来说似乎是错误的,通常在视图之外构造一个演示者,并将视图传递给它。 (因此上面的代码)。您具体的具体情况可能有所不同,但您可能需要发布实际代码而不是伪代码。

我已经尝试过你的情况,然后我遇到了同样的限制。它看起来像

<P extends A<V>, V> 
虽然它们被相同的术语取代,但是2 V被认为可能有所不同。我不能想出他们可能会有所不同的情况(所以到目前为止),所以你会假设他们引用了相同的占位符,但我想它没有办法解决它。

我建议您在View之外重新设计和构建Presenter。然后您的演示者可以毫无问题地了解View(参见上文)。 或者,使用视图的pojo版本从视图构建Presenter。 (查看构造对象,将其提供给演示者)。如果您只需要提供静态版本,这可以工作。然后主持人不知道View,但知道这种表示。