英文:
How to use method with generics and inheritance?
问题
以下是翻译好的内容:
有以下类:
public interface Step<C extends Config> {
void setConfig(C config);
}
public class ValidationStep implements Step<ValidationConf> {
public void setConfig(ValidationConf conf) {}
// implementation
}
public class ProcessStep implements Step<ProcessConf> {
public void setConfig(ProcessConf conf) {}
// implementation
}
public interface Config {
Class<? extends Step> type();
}
public class ValidationConf implements Config {
public Class<? extends Step> type() {
return ValidationStep.class;
}
}
public class ProcessConf implements Config {
public Class<? extends Step> type() {
return ProcessStep.class;
}
}
所以,应用程序需要动态实例化Step子类对象,相应地设置配置并运行步骤,就像这样:
List<Config> configs = loadConfigsFromRepository(); // 包含所有Config的子类型
for (Config conf: configs) {
Step<? extends Config> step = conf.type().getDeclaredConstructor().newInstance();
step.setConfig(conf); // 编译器报错
}
错误信息:
"The method setConfig(capture#8-of ? extends Config) in the type
Step<capture#8-of ? extends Config> is not applicable for the
arguments (Config)".
检查文档,看起来在这种情况下 Java 不会友好:
https://docs.oracle.com/javase/tutorial/java/generics/wildcardGuidelines.html
如何克服这个代码限制 step.setConfig(conf);
的可能解决方案是什么?
编辑 [解决方案]
代码可以在这里查看:https://github.com/danieldestro/cucumber-salad/tree/generics/src/main/java/my/generics
英文:
Having the following classes:
public interface Step<C extends Config> {
void setConfig(C config);
}
and
public class ValidationStep implements Step<ValidationConf> {
public void setConfig(ValidationConf conf) {}
// implementation
}
and
public class ProcessStep implements Step<ProcessConf> {
public void setConfig(ProcessConf conf) {}
// implementation
}
and
public interface Config {
Class<? extends Step> type();
}
and
public class ValidationConf implements Config {
public Class<? extends Step> type() {
return ValidationStep.class;
}
}
and
public class ProcessConf implements Config {
public Class<? extends Step> type() {
return ProcessStep.class;
}
}
so, the application needs to dynamically instantiate Step subclasses objects, set the configuration accordingly and run the step, like this.
List<Config> configs = loadConfigsFromRepository(); // contain all subtypes of Config
for (Config conf: configs) {
Step<? extends Config> step = conf.type().getDeclaredConstructor().newInstance();
step.setConfig(conf); // compiler complains
}
Error message:
> "The method setConfig(capture#8-of ? extends Config) in the type
> Step<capture#8-of ? extends Config> is not applicable for the
> arguments (Config)".
Checking the documentation, looks like Java won´t be friendly in this case:
https://docs.oracle.com/javase/tutorial/java/generics/wildcardGuidelines.html
What are the possible solutions to overcome this code restriction step.setConfig(conf);
?
EDITED [SOLUTION]
Code can be viewed here: https://github.com/danieldestro/cucumber-salad/tree/generics/src/main/java/my/generics
答案1
得分: 2
因为 Step.setConfig(Config)
是一个“消费者”,解决你遇到的“is not applicable for the arguments (Config)
”错误的一种方法是像我在这里演示的使用下界…
…
List<? extends Config> configs = loadConfigsFromRepository(); // 包含所有Config的子类型
for (Config conf : configs) {
Step<? super Config> step = conf.type().getDeclaredConstructor().newInstance();
step.setConfig(conf); // *set*使Step成为一个“消费者”
}
…
这样你就不需要其他答案中提到的类型转换。
我的*loadConfigsFromRepository()
* 实现如下…
static List<? extends Config> loadConfigsFromRepository() {
return of(new ValidationConf(), new ProcessConf());
}
英文:
Because Step.setConfig( Config )
is a „consumer“, one way to resolve the „is not applicable for the arguments (Config)
“ error you get is to use a lower bound like I demonstrate here…
…
List< ? extends Config > configs = loadConfigsFromRepository( ); // contain all subtypes of Config
for ( Config conf: configs ) {
Step< ? super Config > step = conf.type( ).getDeclaredConstructor( ).newInstance( );
step.setConfig( conf ); // *set* makes Step a „consumer“
}
…
That way you don't need the cast that the other answer proposes.
My loadConfigsFromRepository( )
is implemented like…
static List< ? extends Config > loadConfigsFromRepository(){
return of( new ValidationConf( ), new ProcessConf( ) );
}
答案2
得分: 1
去掉通配符。你不需要它。
Step<Config> step = (Step<Config>) conf.type().getDeclaredConstructor().newInstance();
英文:
Get rid of the wildcard. You don't need it.
Step<Config> step = (Step<Config>) conf.type().getDeclaredConstructor().newInstance();
答案3
得分: 0
你的方法并不完全正确。我建议你在确实需要时才使用 Reflections
。
请注意,所有这些实现应该隐藏在包内,只有 Step
接口应该是 public
。Config
实现保存了创建 Step
类所需的所有数据,所以只需要将其委托给这个实现。
package steps;
public interface Step<C extends Config> {
void run(Context context);
}
private final class ValidationStep implements Step<ValidationConf> {
private final ValidationConf config;
public ValidationStep(ValidationConf config) {
this.config = config;
}
}
private class ProcessStep implements Step<ProcessConf> {
private final ProcessConf config;
public ProcessStep(ProcessConf config) {
this.config = config;
}
}
public interface Config {
Step<? extends Config> createStep();
}
private class ValidationConf implements Config {
public Step<ValidationConf> createStep() {
return new ValidationStep(this);
}
}
private class ProcessConf implements Config {
public Step<ValidationConf> createStep() {
return new ProcessConf(this);
}
}
package foo;
List<Config> configs = loadConfigsFromRepository();
for (Config config : loadConfigsFromRepository()) {
config.createStep().run(context);
}
英文:
Your approach is not fully correct. I reccomend you not to use Reflections
until you really need it.
Pay attention, that all these implementation should be hidden inside the package and only Step
interface should be public
. Config
implementation holds all data to create Step
class, so just delegate it to this.
package steps
public interface Step<C extends Config> {
void run(Context context);
}
private final class ValidationStep implements Step<ValidationConf> {
private final ValidationConf config;
public ValidationStep(ValidationConf config) {
this.config = config;
}
}
private class ProcessStep implements Step<ProcessConf> {
private final ProcessConf config;
public ValidationStep(ProcessConf config) {
this.config = config;
}
}
public interface Config {
Step<? extends Config> createStep();
}
private class ValidationConf implements Config {
public Step<ValidationConf> createStep() {
return new ValidationStep(this);
}
}
private class ProcessConf implements Config {
public Step<ValidationConf> createStep() {
return new ProcessConf(this);
}
}
package foo
List<Config> configs = loadConfigsFromRepository();
for (Config config : loadConfigsFromRepository()) {
config.createStep().run(context);
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论