4

私はクラスAを持っています:

public class A {
    private B b = new B() { public void method() { do something } };

    public B getB() { return b; }
}

public interface B { void method(); }

インスタンスbには、その外部クラスのインスタンスの暗黙的な参照があります (これは によって参照できますthis)。これで、別のオブジェクトがbgetter メソッドを介してこれへの参照を取得します。これbは参照のためガベージ コレクションできません。

Aおそらく匿名の内部クラスで明示的な参照をリセットすることにより、囲んでいるインスタンスのガベージコレクションを許可する可能性を得る方法はありますか?

4

2 に答える 2

3

コードが呼び出しB ref = (new A()).getB()た後、Java ヒープにはref、同じ匿名オブジェクトを指す変数が含まれます。この変数(new A()).bは、それを囲む への内部参照を持ちnew A()ます。new A()オブジェクトへの他の参照は存在しません。

あなたの質問は、匿名の b オブジェクトを存続させながら、どうすれば A オブジェクトのガベージ コレクションを強制できるかということです。A への内部参照を使用する b のコードはどうなるでしょうか。

B クラスのコードがそのエンクロージング クラスを参照していないことがわかっている場合は、それを静的に宣言できます。つまり、そのエンクロージング クラスへの内部参照を受け取らないということです。これを行うには、匿名クラスを静的に指定できないため、ネストされたクラスにする必要があります。

public class A {
    static class Bimpl implements B { public void method() { do something } };

    private B b = new Bimpl();

    public B getB() { return b; }
}

public interface B { void method(); }

B ref = (new A()).getB()この状況でコードが呼び出すと、new A()オブジェクトへの参照が存在しないため、オブジェクトはガベージ コレクションに使用できます。

于 2010-01-13T12:47:34.283 に答える
3

技術的に可能です:

public class HasInner {
  public static interface Foo {}

  private static <T> T release(T instance, Object ref) {
    try {
      Class<?> type = instance.getClass();
      for (Field field : type.getFields()) {
        if (!field.isAccessible()) {
          field.setAccessible(true);
        }
        if (field.get(instance) == ref) {
          field.set(instance, null);
        }
      }
    } catch (IllegalAccessException e) {
      throw new IllegalStateException(e);
    }
    return instance;
  }

  public Foo makeFoo() {
    return release(new Foo() {}, this);
  }

  public static void main(String[] args) {
    new HasInner().makeFoo();
  }
}

匿名クラスのjavapインスペクション:

Compiled from "HasInner.java"
final class HasInner$1 extends java.lang.Object implements HasInner$
Foo{
    final HasInner this$0;
    HasInner$1(HasInner);
}

this$0これはコンパイラの実装の詳細であると思われるため、実装はフィールド名に依存していません。

潜在的な問題領域:

  • セキュリティ マネージャは、リフレクション コードを禁止する場合があります。
  • Java プラットフォームが、内部型が外部型を参照する方法を正確に定義しているとは思いません。つまり、これはコンパイラの実装の詳細であり、愚かな場合でも、フィールドに中間ラッパーを含めることは合法です。他のフィールドが存在する場合、参照の曖昧さを解消することは不可能な場合があります。

要するに、私はこれをしません

これが懸念される場合は、プライベートな静的内部クラスを使用してください。

public class A {
  private static class BImpl implements B {
    @Override public void method() {
    }
  }

  private final B b = new BImpl();

  public B getB() { return b; }
}
于 2010-01-13T12:39:31.133 に答える