我知道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
非常感谢。
答案 0 :(得分:2)
有没有办法避免未经检查的演员?
不,因为演员阵容不安全。
考虑以下内容,它满足界限:
class FooView extends BaseView<FooView, FooPresenter>
class BarView extends BaseView<FooView, FooPresenter>
然后在getPresenter()
上致电BarView
。 (V)this
强制转换会将this
(BarView
)投射到V
(FooView
),这是无效的演员。
另外,如果我不在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,但知道这种表示。