gpt4 book ai didi

java - 如何将接口(interface)与通用类的实现绑定(bind)?

转载 作者:行者123 更新时间:2023-11-30 08:01:50 26 4
gpt4 key购买 nike

[Guice 4.0]

我想要一个泛型类的接口(interface),并通过 Guice 在依赖注入(inject)中使用它。对于下面列出的代码,我收到以下错误:

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 class Class1<T1 extends Number, T2 extends Number>
implements InterfClass1<T1, T2> {
public static final String ANNOT1 = "ANNOT1";
public static final String ANNOT2 = "ANNOT2";
private T1 t1;
private T2 t2;
// for the factory
@AssistedInject
public Class1(
@Assisted(Class1.ANNOT1) T1 t1,
@Assisted(Class1.ANNOT2) T2 t2
) {
this.t1 = t1;
this.t2 = t2;
}
public T1 getT1() {
return t1;
}
public T2 getT2() {
return t2;
}
}


public class Module extends AbstractModule {
@Override
protected void configure() {

bind(new TypeLiteral<InterfClass1<Integer, Integer>>(){})
.to(new TypeLiteral<Class1<Integer, Integer>>(){});
}

public static void main(String[] args) {
Injector inj = Guice.createInjector(new Module());
}
}

什么原因导致此错误?

编辑后

让我们添加工厂并修改模块(从模块中删除 InterfClass1 接口(interface)):

public interface Class1Factory<T1 extends Number, T2 extends Number> {
public Class1<T1, T2> createClass1(
@Assisted(Class1.ANNOT1) T1 t1,
@Assisted(Class1.ANNOT2) T2 t2
);
}

public class Module extends AbstractModule {
@Override
protected void configure() {
install(new FactoryModuleBuilder()
.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);
}
}

效果很好!

现在让我们合并界面:

public class Module extends AbstractModule {
@Override
protected void configure() {
bind(new TypeLiteral<InterfClass1<Integer, Double>>(){})
.to(new TypeLiteral<Class1<Integer, Double>>(){});
install(new FactoryModuleBuilder()
.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);
}
}

我们得到:

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)

好吧,不管错误如何,我们也更改工厂:

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) 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)

但是,如果我删除模块中接口(interface)和类之间的关系并将此关系添加到工厂的规范中,则不会出现错误:

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);
}
}

效果很好!

为什么 Guice 有这种奇怪的行为?为什么无论工厂如何,我都无法将接口(interface)与实现类关联起来?

最佳答案

我无法确切地弄清楚您想要做什么,但在我看来,您实际上并没有尝试创建 AssistedInject 工厂,因为您还没有为工厂创建接口(interface)。在这种情况下,您根本不需要使用 @Assisted 参数。您的构造函数应如下所示(对该类没有其他更改):

@Inject
public Class1(
@Named(Class1.ANNOT1) T1 t1,
@Named(Class1.ANNOT2) T2 t2
) {

然后,指定模块中的绑定(bind)。您必须明确告诉 Guice 为参数注入(inject)什么以及您指定的注释:

@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());
}

正如您在运行它时所看到的,它将注入(inject)一个 Class 实现,并指定两个参数:

class guice.Class1
T1: 5 T2: 15
<小时/>

如果您尝试使用 AssistedInject 构建 Class1 对象工厂,则由于您指定 Generit 类型参数的方式,这会变得更加困难。不幸的是,你不能inject a generic factory using AssistedInject in the normal way ,这会变得更加困难,因为您的 Class1 实现需要 T1 extends Number,但您的接口(interface)可以是您想要的任何 T1。这意味着您的工厂必须将其接收的输入参数的类型限制为 Number 的子类;换句话说,您的工厂不能只创建它想要的任何 InterfClass1,它只能创建具有正确输入参数的实例。

希望答案的前半部分就是您想要做的。如果不是,我们需要有关您的用例的更多信息才能回答此问题。

关于java - 如何将接口(interface)与通用类的实现绑定(bind)?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31807055/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com