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

のコンストラクターhelperMethod内から呼び出していませんか? Helper投稿したコードからその部分を省略しましたが、表示されている動作と一致します。

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が設定される前でも発生するため、Foo でオーバーライドされたメソッドはaaanull と見なされます。私の例のように、これは Guice に固有のものではありませんが、Guice インジェクションは、他のものと同じようにコンストラクターをトリガーできます。

この StackOverflow の回答では、この問題についてより徹底的に説明しています。

于 2013-10-01T05:29:47.407 に答える