Allowing garbage collection of a class while an anonymous inner class instance is referenced elsewhere?

garbage-collection, inner-classes, java

Solution

It is technically possible:

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

The javap inspection of the anonymous class:

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

The implementation does not rely on the field name being `this$0` as I suspect this is a compiler implementation detail.

Potential problem areas:

- A security manager may forbid the reflection code.

- I don't think the Java platform defines exactly how the inner type refers to the outer. That is, it is a compiler implementation detail and it would be legal, if stupid, to have an intermediary wrapper in the field - in the presence of other fields, disambiguating the reference may be impossible.

In short, I would never do this.

If this is a concern, use a private static inner class:

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

  private final B b = new BImpl();

  public B getB() { return b; }
}

Problem

I have a class A: ``` public class A { private B b = new B() { public void method() { do something } }; public B getB() { return b; } } public interface B { void method(); } ``` The instance `b` has an implicit reference of the instance of its outer class (that can be referenced by `this`). Now another object gets a reference to this `b` via the getter method. This `b` cannot be garbage collected due to the reference. Is there a way to get a possibility to allow a garbage collection of the enclosing `A` instance, maybe via resetting an explicit reference in the anonymous inner class?

Original source