[英]Can I avoid this unchecked cast using self-bound generics and subclassing in Java?
我知道在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
非常感谢。
有什么办法避免不受限制的演员表吗?
不可以,因为演员阵容不安全。
考虑满足边界的以下内容:
class FooView extends BaseView<FooView, FooPresenter>
class BarView extends BaseView<FooView, FooPresenter>
然后在BarView
上调用getPresenter()
。 在(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;
}
这将使您的班级紧密地联系在一起,从看来只能进行双重派遣。 我认为您正在达到泛型可以做到这一点的界限,但是您可以以不同的方式实现相同目标。
因此,这不是您问题的直接答案,而是可能的替代方法:
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,但2 V可能会有所不同。 我无法想出(到目前为止)它们可能不同的情况,因此您可以假定它们将引用相同的占位符,但是我想没有办法解决。
我建议您在View之外重新设计和构造Presenter。 这样,您的演示者便可以毫无问题地了解View(请参见上文)。 或者,使用pojo版本的视图从视图构造Presenter。 (视图构造对象,并将其提供给演示者)。 如果您只需要提供静态版本,则可以使用此功能。 然后,演示者不知道View,但是知道这种表示。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.