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

@Provides with @Named doesn't work for supertype declared variables

我目前正在探索 Guice 功能并遇到了一个奇怪的行为 - 当我将变量声明为

@Inject
@Named("dragon")
Dragon dragon2;

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

@Inject
@Named("dragon")
Creature dragon2;

我收到一个错误

未绑定带有 @com.google.inject.name.Named(value=dragon) 注释的 warlock.rincewind.creatures.Creature 的实现。

这是我的提供者方法:

@Named("dragon")
@Provides
public Dragon providesDragon() {
    Dragon d = new Dragon("Morkeleb");
    return d;
}

我知道,有很多不同的方法可以克服这个问题(最简单的方法是更改​​为 Creature 提供 return 类型),但我正在尝试找出造成这种限制的原因。

考虑,例如:

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

您的注入如何知道是在此处绑定 Dragon 还是 Dog

不能! 注入密钥不是协变的。您需要做的是,指定您要注入的子类,并将其绑定到您要注入的接口或超类。 换句话说:

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

这会给你想要的行为。当然,您仍然可以专门为 Dragon 绑定注入。