繁体   English   中英

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

[英]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 )至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;
}

这将使您的班级紧密地联系在一起,从看来只能进行双重派遣。 我认为您正在达到泛型可以做到这一点的界限,但是您可以以不同的方式实现相同目标。

因此,这不是您问题的直接答案,而是可能的替代方法:

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM