Java 如何将接口与泛型类的实现绑定?

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

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