gpt4 book ai didi

java - 如何确保这是我的类签名中引用的泛型类型?

转载 作者:搜寻专家 更新时间:2023-11-01 02:20:35 26 4
gpt4 key购买 nike

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

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 可能是一些其他抽象引擎并且没有办法知道我们调用它的子类是否实际上是一个 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。抽象规则已经保证这是一个安全的操作,所以如果您将参数更改为仅允许任何引擎,它就会起作用。

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 个绑定(bind)在一起的类,并将交互调用移至包装器。

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 是一个语义接口(interface),用于说明这些类之间的相互对话在语义上是否有意义。 (物理引擎和光引擎可能共享一些功能,但让它们互换是没有意义的。)

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!");
}
}

}

关于java - 如何确保这是我的类签名中引用的泛型类型?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45444424/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com