Java 如何将接口与泛型类的实现绑定?
[Guice 4.0] 我希望为泛型类提供一个接口,并使用Guice在依赖项注入中使用它。 对于下面列出的代码,我得到以下错误:Java 如何将接口与泛型类的实现绑定?,java,generics,inheritance,dependency-injection,guice,Java,Generics,Inheritance,Dependency Injection,Guice,[Guice 4.0] 我希望为泛型类提供一个接口,并使用Guice在依赖项注入中使用它。 对于下面列出的代码,我得到以下错误: Exception in thread "main" com.google.inject.CreationException: Unable to create injector, see the following errors: 1) Could not find a suitable constructor in com.ulmon.fsqtransit.gu
Exception in thread "main" com.google.inject.CreationException: Unable to create injector, see the following errors:
1) Could not find a suitable constructor in com.ulmon.fsqtransit.guicetest.Class1. Classes must have either one (and only one) constructor annotated with @Inject or a zero-argument constructor that is not private.
at com.ulmon.fsqtransit.guicetest.Class1.class(Class1.java:14)
at com.ulmon.fsqtransit.guicetest.Module.configure(Module.java:14)
--
好的,让我们不考虑错误,也更改工厂:
public interface Class1Factory<T1 extends Number, T2 extends Number> {
public InterfClass1<T1, T2> createClass1(
@Assisted(Class1.ANNOT1) T1 t1,
@Assisted(Class1.ANNOT2) T2 t2
);
}
公共接口工厂{
公共干预类别1创建类别1(
@辅助(1类ANNOT1)T1,
@辅助(1.ANNOT2类)T2
);
}
我们得到:
1) Could not find a suitable constructor in com.ulmon.fsqtransit.guicetest.Class1. Classes must have either one (and only one) constructor annotated with @Inject or a zero-argument constructor that is not private.
at com.ulmon.fsqtransit.guicetest.Class1.class(Class1.java:15)
at com.ulmon.fsqtransit.guicetest.Module.configure(Module.java:14)
1) Could not find a suitable constructor in com.ulmon.fsqtransit.guicetest.Class1. Classes must have either one (and only one) constructor annotated with @Inject or a zero-argument constructor that is not private.
at com.ulmon.fsqtransit.guicetest.Class1.class(Class1.java:15)
at com.ulmon.fsqtransit.guicetest.Module.configure(Module.java:14)
2) com.ulmon.fsqtransit.guicetest.InterfClass1<java.lang.Integer, java.lang.Double> is an interface, not a concrete class. Unable to create AssistedInject factory.
while locating com.ulmon.fsqtransit.guicetest.InterfClass1<java.lang.Integer, java.lang.Double>
at com.ulmon.fsqtransit.guicetest.Class1Factory.createClass1(Class1Factory.java:1)
1)在com.ulmon.fsqtransit.guicetest.Class1中找不到合适的构造函数。类必须有一个(并且只有一个)用@Inject注释的构造函数,或者一个非私有的零参数构造函数。
位于com.ulmon.fsqtransit.guicetest.Class1.class(Class1.java:15)
位于com.ulmon.fsqtransit.guicetest.Module.configure(Module.java:14)
2) com.ulmon.fsqtransit.guicetest.interfclass是一个接口,而不是一个具体的类。无法创建辅助对象工厂。
查找com.ulmon.fsqtransit.guicetest.interfclass时
在com.ulmon.fsqtransit.guicetest.classfactory.createClass1(classfactory.java:1)上
但是,如果我删除模块中接口和类之间的关系,并将此关系添加到工厂规范中,则不会出现错误:
public class Module extends AbstractModule {
@Override
protected void configure() {
install(new FactoryModuleBuilder()
.implement(new TypeLiteral<InterfClass1<Integer, Double>>(){}
, new TypeLiteral<Class1<Integer, Double>>(){})
.build(new TypeLiteral<Class1Factory<Integer, Double>>(){}));
}
public static void main(String[] args) {
Injector inj = Guice.createInjector(new Module());
Class1Factory f = inj.getInstance(Key.get(new TypeLiteral<Class1Factory<Integer, Double>>(){}));
f.createClass1(10, 11.0);
}
}
公共类模块扩展了AbstractModule{
@凌驾
受保护的void configure(){
安装(新FactoryModuleBuilder()
.implement(新的TypeLiteral(){}
,新的TypeLiteral(){})
.build(新的TypeLiteral(){});
}
公共静态void main(字符串[]args){
Injector inj=Guice.createInjector(新模块());
class1工厂f=inj.getInstance(Key.get(new-TypeLiteral(){}));
f、 createClass1(10,11.0);
}
}
它工作得很好强>
为什么Guice有这种奇怪的行为?为什么不管工厂是什么,我都无法将接口与实现类关联起来?我无法确切地理解您试图做什么,但在我看来,您实际上并没有试图创建一个AssistedInject工厂,因为您还没有为工厂创建接口。在这种情况下,您根本不需要使用
@Assisted
参数。您的构造函数应该如下所示(对类没有其他更改):
然后,在模块中指定绑定。您必须显式地告诉Guice要为参数和指定的注释注入什么:
@Override
protected void configure() {
bind(new TypeLiteral<InterfClass1<Integer, Integer>>(){})
.to(new TypeLiteral<Class1<Integer, Integer>>(){});
bind(Integer.class)
.annotatedWith(Names.named(Class1.ANNOT1))
.toInstance(5);
bind(Integer.class)
.annotatedWith(Names.named(Class1.ANNOT2))
.toInstance(15);
}
如果您正在尝试使用AssistedInject构建
Class1
对象的工厂,这将非常困难,因为您指定了generit类型参数的方式。不幸的是,您不能这样做,这就更加困难了,因为您的Class1
实现需要T1扩展数字
,但是您的接口可以是您想要的任何T1
。这意味着您的工厂必须将其接收的输入参数的类型限制为Number
的子类;换句话说,您的工厂不能创建它想要的任何interfclas1
,它只能创建具有正确输入参数的实例
希望答案的前半部分是你想要做的。如果不是,我们需要关于您的用例的更多信息来回答这个问题。谢谢您的回答!但是,我无法理解为什么我不能在使用工厂时也这样做,特别是考虑到这样一个事实,即如果我删除接口和类之间的绑定,并将此绑定添加到工厂的“配置”(
.implement(…)
)中,它就可以工作。请查看我的更新文本,以“编辑后”开头。
1) Could not find a suitable constructor in com.ulmon.fsqtransit.guicetest.Class1. Classes must have either one (and only one) constructor annotated with @Inject or a zero-argument constructor that is not private.
at com.ulmon.fsqtransit.guicetest.Class1.class(Class1.java:15)
at com.ulmon.fsqtransit.guicetest.Module.configure(Module.java:14)
2) com.ulmon.fsqtransit.guicetest.InterfClass1<java.lang.Integer, java.lang.Double> is an interface, not a concrete class. Unable to create AssistedInject factory.
while locating com.ulmon.fsqtransit.guicetest.InterfClass1<java.lang.Integer, java.lang.Double>
at com.ulmon.fsqtransit.guicetest.Class1Factory.createClass1(Class1Factory.java:1)
public class Module extends AbstractModule {
@Override
protected void configure() {
install(new FactoryModuleBuilder()
.implement(new TypeLiteral<InterfClass1<Integer, Double>>(){}
, new TypeLiteral<Class1<Integer, Double>>(){})
.build(new TypeLiteral<Class1Factory<Integer, Double>>(){}));
}
public static void main(String[] args) {
Injector inj = Guice.createInjector(new Module());
Class1Factory f = inj.getInstance(Key.get(new TypeLiteral<Class1Factory<Integer, Double>>(){}));
f.createClass1(10, 11.0);
}
}
@Inject
public Class1(
@Named(Class1.ANNOT1) T1 t1,
@Named(Class1.ANNOT2) T2 t2
) {
@Override
protected void configure() {
bind(new TypeLiteral<InterfClass1<Integer, Integer>>(){})
.to(new TypeLiteral<Class1<Integer, Integer>>(){});
bind(Integer.class)
.annotatedWith(Names.named(Class1.ANNOT1))
.toInstance(5);
bind(Integer.class)
.annotatedWith(Names.named(Class1.ANNOT2))
.toInstance(15);
}
public static void main(String[] args) {
Injector inj = Guice.createInjector(new Module());
InterfClass1<Integer, Integer> interf =
inj.getInstance(Key.get(new TypeLiteral<InterfClass1<Integer, Integer>>(){}));
System.out.println(interf.getClass());
System.out.println("T1: " + interf.getT1() + " T2: " + interf.getT2());
}