2

Here is an example of the issue I've come across:

public interface IFoo { ... }

public abstract class Helper implements IFoo {
  public Helper() { ... }

  protected abstract X helperMethod();
}    

public class Foo extends Helper {
  private final String aaa;

  @Inject
  public Foo(String aaa) { this.aaa = aaa; }

  @Override
  X helperMethod() { doSomethingUsingWhatsInjected(aaa); }
}

The issue is that when I bind IFoo to Foo like this:

bind(IFoo.class).to(Foo.class).in(Singleton.class);

it appears like helperMethod() is being called before the aaa has been Injected since I'm seeing aaa as null. But if I instead don't use the class Helper and in-line all of its code directly in Foo, guice doesn't struggle.

What's the difference between these two approaches? Why is helperMethod() called before we know from where we're getting the implementation of IFoo? Can we use Helper along with injection?

4

1 回答 1

2

你确定你不是helperMethodHelper构造函数中调用的吗?您从发布的代码中省略了该部分,但它与您看到的行为相匹配。

public class Test {
  interface IFoo { }

  static abstract class Helper implements IFoo {
    Helper() { helperMethod(); }
    abstract void helperMethod();
  }

  static class Foo extends Helper {
    private final String aaa;

    Foo(String aaa) { this.aaa = aaa; }

    @Override
    void helperMethod() { System.out.println(String.valueOf(aaa)); }
  }

  public static void main(String[] args) {
    // Call helperMethod twice:
    // once in the Helper.Helper(), once right here.
    new Foo("expected").helperMethod();
    // output:
    //   null
    //   expected
  }
}

Foo 做的第一件事是隐式调用它的超类构造函数,就好像你输入了super(); 这必然作为子类构造函数中的第一条语句发生。因此,这甚至在aaa设置 final 变量之前发生,因此您在 Foo 中的覆盖方法aaa视为 null。在我的例子中,这不是 Guice 特有的,但是 Guice 注入可以像其他任何东西一样触发构造函数。

这个 StackOverflow 答案提供了对这个问题的更彻底的讨论。

于 2013-10-01T05:29:47.407 回答