假设我们有三个类-AbstractMessageAbstractEngineAbstractAction。这三个类都以通用方式互相引用,因此每个引擎都有对应的消息和操作,您可以在代码中直接引用它们。

public class MyMessage<M extends AbstractMessage<M,E,A>, E extends AbstractEngine<M,E,A>, A extends AbstractAction<M,E,A>> {

这很好,但是当我尝试以最高级别实施行为时,我遇到了一些问题。我的AbstractAction类具有一个由此定义的applyTo方法:
protected abstract M applyTo(E engine, Object guarantee);

我的AbstractEngine类有这个
private final M apply(A action) {
    return action.apply(this, this.guarantee);
}

正是在这条线上,它令人沮丧-抱怨:
The method applyTo(E, Object) in the type AbstractAction<M,E,A> is not
applicable for the arguments (AbstractEngine<M,E,A>, Object)

现在,这样做的原因很明显-所讨论的E可能是其他OTHER AbstractEngine,并且无法知道我们从中调用的子类是否实际上是E

我的问题是,我如何确定地说如果您要使用class MyEngine extends AbstractEngine<M...,E...,A...>,那么MyEngine,必须E?并将这种确定性转化为AbstractEngine吗?

这是一个说明问题的小例子。
class EngineExample {

    static abstract class AbEng<A extends AbAct<A,M,E>, M extends AbMes<A,M,E>, E extends AbEng<A,M,E>> {

        final M func(A act) {
            return act.apply(this); // compile error here
        }

    }

    static abstract class AbMes<A extends AbAct<A,M,E>, M extends AbMes<A,M,E>, E extends AbEng<A,M,E>> {

    }

    static abstract class AbAct<A extends AbAct<A,M,E>, M extends AbMes<A,M,E>, E extends AbEng<A,M,E>> {

        abstract void apply(E e);

    }

    static class RealEng extends AbEng<RealAct, RealMes, RealEng> {

    }

    static class RealMes extends AbMes<RealAct, RealMes, RealEng> {

    }

    static class RealAct extends AbAct<RealAct, RealMes, RealEng> {

        void apply(RealEng eng) {
            System.out.println("applied!");
        }
    }

}

最佳答案

使用最宽松的有效参数类型

最简单的解决方案是不实际执行this isInstanceOf E。抽象规则已经保证了此操作是安全的,因此,如果您将参数更改为仅允许任何Engine,则它将起作用。

abstract Action<E> {
  public void apply(Engine<?> e, Object o) {
    e.doSomething(o);
  }
}

要么
abstract Action<E> {
  <T extends Engine<?>> public T apply(T e, Object o) {
    return e.doSomething(o);
  }
}

使用类型安全的包装器

另一个解决方案是创建将这3个绑定在一起的另一个类,并将交互调用移至包装器。
abstract System<A extends Action, M extends Message, E extends Engine> {
    abstract void apply(A action, E engine) {
        engine.render(action.apply())
    }
}

或者让包装器类使用这3个实例,并使用传入的版本。基本上,这是“允许任何东西足够接近”的解决方案,并添加了另一个类来管理彼此之间如何交谈。

预制检查

如果强制转换设置无效,您还可以对构造进行参考强制转换以引发错误。
private final E dis = (E) this;

这实际上只是将问题从始终在编译时转移到了有时在运行时,所以通常,这不是一个安全/稳定的解决方案。

下一个解决方案针对您的情况(使用我们讨论中的信息)。基本上,您想在抽象类中定义一个方法,类A和B可以继承该方法,但是A和B不应使用其基类互换。

只需使用多态性并将泛型用作类型分隔符

这是对MVCe的修改,改用多态性,仅将泛型用作一种类型类别排他锁机制。基本上,Type是一个语义接口,用于说明是否在语义上使这些类相互交谈是有意义的。 (物理引擎和光引擎可能共享某些功能,但是让它们可以互换是没有意义的。)
class test {

    public static void main(String[] rawrs) {
        RealEng re = new RealEng();
        RealAct ra = new RealAct();
        MockAct ma = new MockAct();
        ra.apply(re);
        // Remove all code related to Type interface if next line should compile
        ma.apply(re); // compile error here
    }

    static interface Type {
    }

    static interface Real extends Type {
    };

    static interface Mock extends Type {
    };

    static abstract class AbEng<T extends Type> {

        final void func(AbAct<T> act) {
            act.apply(this); // compile error here
        }

    }

    static abstract class AbMes<T extends Type> {

    }

    static abstract class AbAct<T extends Type> {

        abstract void apply(AbEng<T> e);

    }

    static class RealEng extends AbEng<Real> {

    }

    static class RealMes extends AbMes<Real> {

    }

    static class RealAct extends AbAct<Real> {
        @Override
        void apply(AbEng<Real> eng) {
            System.out.println("applied!");
        }
    }

    static class MockAct extends AbAct<Mock> {
        @Override
        void apply(AbEng<Mock> eng) {
            System.out.println("applied!");
        }
    }

}

10-06 13:42