提问人:QuirkyBit 提问时间:1/20/2021 最后编辑:QuirkyBit 更新时间:1/20/2021 访问量:3892
参数化类“ABC”的原始使用
Raw use of parameterized class 'ABC'
问:
我有以下界面:
public interface AsynchronousJobRunner<T extends AsynchronousJob> extends Runnable {
public void kill();
public void addJobExecutionListener(JobExecutionListener listener);
public void removeJobExecutionListener(JobExecutionListener listener);
public AsynchronousJobRunner withJob(T job);
}
AsynchronousJob
是一个抽象类,可以使用以下抽象方法进行扩展以表示其他作业:
public abstract class AsynchronousJob implements JSONSerializable, HasId {...}
/**
* Returns the class of the {@link AsynchronousJobRunner} that runs this type of job.
* @return The appropriate class of the job runner for this class.
*/
public abstract Class<? extends AsynchronousJobRunner> jobRunnerClass();
我还有以下内容,它扩展了基类,并具有以下签名和方法:ExportJob
public class ExportJobRunner extends BaseJobRunner<ExportJob> { ...}
@Override
public Class<? extends AsynchronousJobRunner> jobRunnerClass() {
return ExportJobRunner.class;
}
这两种方法都有警告。jobRunnerClass()
Raw use of parameterized class 'AsynchronousJobRunner'
使警告消失的简单解决方案是:
public abstract Class<? extends AsynchronousJobRunner<?>> jobRunnerClass();
@Override
public Class<? extends AsynchronousJobRunner<?> jobRunnerClass() {
return ExportJobRunner.class;
}
但什么是正确的解决方案,为什么/如何?
编辑:
我最终只是简单地将接口的代码更改为:
public interface AsynchronousJobRunner<T extends AsynchronousJob<T>> extends Runnable {
void kill();
void addJobExecutionListener(JobExecutionListener listener);
void removeJobExecutionListener(JobExecutionListener listener);
AsynchronousJobRunner<T> withJob(T job);
}
对类的更改:AsynchronousJob
public abstract class AsynchronousJob<T> implements JSONSerializable, HasId { ...
/**
* Returns the class of the {@link AsynchronousJobRunner} that runs this type of job.
* @return The appropriate class of the job runner for this class.
*/
public abstract Class<? extends AsynchronousJobRunner<? extends AsynchronousJob<T>> jobRunnerClass();
}
ExportJob
类:
public public class ExportJob extends AsynchronousJob<ExportJob> {...
@Override
public Class<? extends AsynchronousJobRunner<? extends AsynchronousJob<ExportJob>>> jobRunnerClass() {
return ExportJobRunner.class;
}
}
班级保持不变。ExportJobRunner
我还忘了提到,由于作业被序列化到数据库,因此发生了一些注入魔术:
/**
* Instantiates an {@link AsynchronousJobRunner} instance for the provided job.
* <p>
* In order for the creation of the runner to succeed, the {@link AsynchronousJob#jobRunnerClass()}
* method of the job must specify the appropriate class for its runner.
*
* @param job job to create runner for
* @return job runner configured for the specified {@code job} parameter
*/
private <T extends AsynchronousJob<T>> AsynchronousJobRunner<T> createJobRunner(T job) {
return ((AsynchronousJobRunner<T>)injector.getInstance(job.jobRunnerClass())).withJob(job);
}
我已经接受了 Vershinin @Andrew回答,因为他让我走上了正确的思想轨道。
答:
2赞
Andrew Vershinin
1/20/2021
#1
我认为,你可以采用这个递归声明:AsynchronousJob
public abstract class AsynchronousJob<T extends AsynchronousJob<T>>
implements JSONSerializable, HasId {
public abstract Class<? extends AsynchronousJobRunner<T>> jobRunnerClass();
//...
}
不要忘记相应地更新定义:AsynchronousJobRunner
public interface AsynchronousJobRunner<T extends AsynchronousJob<T>> //...
然后,在作业类中,可以在返回类型中使用类本身:
public class ExportJob extends AsynchronousJob<ExportJob> {
@Override
public Class<? extends AsynchronousJobRunner<ExportJob>> jobRunnerClass() {
return ExportJobRunner.class;
}
}
通过这种方式,您可以确保类型一致性:类型的作业返回运行器类型,这些运行器类型运行此类类型的作业 - 您无法通过在签名中使用来确保这一点,因为您可以返回任何运行器类型并且它会编译。T
? extends AsynchronousJob
jobRunnerClass
评论
0赞
QuirkyBit
1/20/2021
解决方案最终与您提出的略有不同(并且递归较少),但您的回答让我走上了正确的轨道。
0赞
Andrew Vershinin
1/20/2021
@QuirkyBit 如果你不介意分享,你最终得到了什么?
0赞
QuirkyBit
1/20/2021
我在阅读您的答案后沉思了一下这个问题。
1赞
Andrew Vershinin
1/20/2021
@QuirkyBit,是的,这有效,但正如我所提到的,您不会对运行器作业类型进行编译时错误检查。
0赞
QuirkyBit
1/20/2021
是的,我可能需要对我需要更改的代码和类进行更长的思考。您的回答确实有帮助,再次感谢您!
下一个:如何覆盖使用原始类型的方法?
评论
AsynchronousJobRunner
AsynchronousJob