@Provides with @Named不适用于超类型声明的变量

skw*_*aar 7 java guice

我正在探索Guice功能并面临一种奇怪的行为 - 当我声明变量为

@Inject
@Named("dragon")
Dragon dragon2;
Run Code Online (Sandbox Code Playgroud)

注入按预期工作,但是当我想将dragon2声明为接口(它实现了Creature)时,即

@Inject
@Named("dragon")
Creature dragon2;
Run Code Online (Sandbox Code Playgroud)

我收到一个错误

没有实现warlock.rincewind.creatures.Creature注释与@com.google.inject.name.Named(value=dragon)绑定.

这是我的提供者方法:

@Named("dragon")
@Provides
public Dragon providesDragon() {
    Dragon d = new Dragon("Morkeleb");
    return d;
}
Run Code Online (Sandbox Code Playgroud)

我知道,有很多不同的方法可以克服这个问题(最简单的方法是将更改类型提供给Creature),但我试图找到这种限制的原因.

dur*_*597 9

例如,考虑一下:

interface Creature { }

class Dragon implements Creature { }
class Dog implements Creature { }

public class Kennel {
    @Inject @Named("foo") Creature c;
}

public class KennelModule extends Abstract Module {
    @Override
    protected void configure() {
        bind(Dragon.class).annotatedWith(Names.named("foo"));
        bind(Dog.class).annotatedWith(Names.named("foo"));
    }
}
Run Code Online (Sandbox Code Playgroud)

你的注射怎么会知道是绑定Dragon还是Dog在这里?

它不能!注入键不协变.您需要做的是,指定要注入的子类,并将其绑定到您要注入的接口或超类.换一种说法:

public class KennelModule extends Abstract Module {
    @Override
    protected void configure() {
        bind(Creature.class).annotatedWith(Names.named("foo").to(Dragon.class);
    }
}
Run Code Online (Sandbox Code Playgroud)

这将为您提供所需的行为.当然,你还可以Dragon特意绑定注射剂.