泛型类型的args具体是哪个扩展类?

时间:2020-03-06 14:56:04  来源:igfitidea点击:

我想要一个实现接口的类,该接口将特定的子类指定为参数。

public abstract Task implements TaskStatus<Task> {
  TaskStatus<T> listener;

  protected complete() {
      // ugly, unsafe cast
      callback.complete((T) this);
  }
}

public interface TaskStatus<T> {
   public void complete(T task);
}

但是我要保证使用的type-arg不仅仅是扩展该任务的特定类,而不仅仅是任务or。

因此,我想出的最好的方法是:

public abstract Task<T extends Task> implements TaskStatus<T> {
}

我们可以通过编写以下内容来扩展它:

public class MyTask extends Task<MyTask> {
}

但这也是有效的:

public class MyTask extends Task<SomeOtherTask> {
}

并且回调的调用将与ClassCastException一起炸毁。那么,这种方法是错误的又是折断的,还是有一种正确的方法使我错过了呢?

解决方案

目前尚不清楚我们要在"任务"内部执行的操作。但是,如果我们按如下方式定义通用类Task &lt;T>

class Task<T extends Task<T>> { ... }

可能有以下两种:

class MyTask extends Task<MyTask> { ... }
class YourTask extends Task<MyTask> { ... }

但是以下是禁止的:

class MyTask extends Task<String> { ... }

以上"任务"的定义使用了F界多态性,这是一个相当高级的功能。我们可以查看研究论文"面向对象编程的F界多态性"以获取更多信息。

我在理解我们要通过此方法完成的工作时遇到了一些麻烦。我们能否提供更多详细信息?

我对代码的阅读表明,我们有这些任务将被子类化,并且在任务完成后,执行线程将在该任务上调用complete()。此时,我们想调用一个回调并将其传递给子类对象。我认为这是问题所在。我们正在尝试将有关潜在子类的知识放入抽象类中,这是禁止的。

这也引发了一个问题,如果可以进行此调用,那么与超类不同的子类的回调将如何处理?

我建议添加一个getThis,它应该返回正确键入的内容。当然,subclas可能行为不当,但这始终是事实。我们避免的是强制转换和ClassCastException的可能性。

public abstract class Task<THIS extends Task<THIS>> {
    private TaskStatus<THIS> callback;

    public void setCallback(TaskStatus<THIS> callback) {
        this.callback = callback==null ? NullCallback.INSTANCE : callback;
    }

    protected void complete() {
        // ugly, unsafe cast
        callback.complete(getThis());
    }

    protected abstract THIS getThis();
}

public interface TaskStatus<T/* extends Task<T>*/> {
    void complete(T task);
}

public class MyTask extends Task<MyTask> {
    @Override protected MyTask getThis() {
        return this;
    }
}

建设者经常会遇到这个问题。

我真的只有在构造函数中强制使用arg类型时才能看到此方法。通过。内省和Class.getSuperType(),我们可以检查args类型,并验证arg类型与该类匹配。

遵循以下原则:

assert getClass() == ((ParameterizedType) getSuperType()).getTypeArguments()[0];

(这是我的脑袋,请检查JavaDocs进行验证)。

我不确定在代码中在哪里创建回调。我们已经在顶部省略了它的声明。

另一种方法是删除不安全的演员表,例如atm。我看不到有完整的流程可以找出为什么我们需要不安全的演员表。