我希望有一个实现接口的类,它将特定的子类指定为参数。
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);
}
但不是仅仅是任务,或者,我想保证使用的类型arg是扩展此类的特定类的类型。
所以我想出的最好的是:
public abstract Task<T extends Task> implements TaskStatus<T> {
}
你可以通过写下来扩展它:
public class MyTask extends Task<MyTask> {
}
但这也是有效的:
public class MyTask extends Task<SomeOtherTask> {
}
并且回调的调用会因ClassCastException而爆炸。那么,这种方法是错误的还是破碎的,还是有正确的方法来做到这一点我不知何故错过了?
答案 0 :(得分:2)
目前尚不清楚你在Task
内想要做什么。但是,如果您按如下方式定义泛型类Task<T>
:
class Task<T extends Task<T>> { ... }
以下两种是可能的:
class MyTask extends Task<MyTask> { ... }
class YourTask extends Task<MyTask> { ... }
但禁止以下内容:
class MyTask extends Task<String> { ... }
Task
的上述定义使用F-bounded多态,这是一个相当高级的特性。您可以查看研究论文“F-bounded polymorphism for object-oriented programming”以获取更多信息。
答案 1 :(得分:1)
我建议添加一个getThis,它应该返回适当的类型。当然,一个子类可能行为不端,但这总是如此。你避免的是演员阵容和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;
}
}
这个问题经常出现在构建者身上。
答案 2 :(得分:0)
我很难理解你要通过这个来完成什么。你能提供更多细节吗?
我对代码的阅读说明你有这些任务将被分类,并且在任务完成后,执行线程将在任务上调用complete()。此时,您需要调用回调并将其传递给子类对象。我认为这是问题所在。您正试图将潜在子类的知识放入您的抽象类中,这是一个禁忌。
这也提出了一个问题,如果你可以进行这个调用,那么与超类不同的子类的回调是什么?
答案 3 :(得分:0)
如果你在构造函数中强制执行arg类型,我真的只能看到这个工作。通过。内省和Class.getSuperType()可以检查类型args,并验证类型arg是否与此类匹配。
沿着以下方向做的事:
assert getClass() == ((ParameterizedType) getSuperType()).getTypeArguments()[0];
(这是从头到尾,检查JavaDocs验证)。
我不确定在代码中创建回调的位置。你在顶部省略了它的声明。
另一条路线是移除不安全的演员阵容,如atm。我无法看到完整的流程来发现你为何需要不安全的演员。