Consentire la raccolta dei rifiuti di una classe, mentre un anonimo istanza di una classe interna viene fatto riferimento altrove?

StackOverflow https://stackoverflow.com/questions/2056205

Domanda

Ho una classe A:

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

    public B getB() { return b; }
}

public interface B { void method(); }

Il b istanza ha un riferimento implicito dell'istanza della sua classe esterna (che possono fare riferimento this). Ora un altro oggetto ottiene un riferimento alla presente b attraverso il metodo getter. Questo b non può essere garbage collection causa del riferimento.

C'è un modo per ottenere la possibilità di consentire una garbage collection dell'istanza racchiude A, forse tramite il reset di un esplicito riferimento nella classe interna anonima?

È stato utile?

Soluzione

E 'tecnicamente possibile:

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 di ispezione della classe anonima:

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

L'implementazione non si basa sul nome del campo essendo this$0 come ho il sospetto che questo è un dettaglio di implementazione del compilatore.

aree potenziale problema:

  • Un responsabile della sicurezza può sospendere il codice di riflessione.
  • non che la piattaforma Java definisce esattamente come il tipo interno si riferisce a quello esterno. Cioè, si tratta di un dettaglio di implementazione del compilatore e sarebbe legale, se stupido, di avere un involucro intermediario nel campo -. In presenza di altri campi, disambiguare il riferimento può essere impossibile

In breve, vorrei mai fare questo .

Se questo è un problema, utilizzare una classe interna private static :

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

  private final B b = new BImpl();

  public B getB() { return b; }
}

Altri suggerimenti

Dopo le chiamate di codice B ref = (new A()).getB() mucchio Java conterrà un ref variabile che indicano lo stesso oggetto anonimo come (new A()).b che a sua volta ha un riferimento interno al suo new A() racchiude. Non esistono altri riferimenti all'oggetto new A().

La tua domanda è, come possiamo forzare una garbage collection di un oggetto, mantenendo vivo l'oggetto B anonimo? La risposta è che non è possibile, perché se si potesse, cosa sarebbe successo con il codice in B che utilizza il riferimento interno di un?

Se si sa che il codice della classe B non fa riferimento la sua classe di inclusione, è possibile dichiarare che statica, il che significa che non riceverà un riferimento interno alla sua classe enclusing. Per fare questo è necessario per rendere una classe annidata, come non si può spaecify classi anonime essere statico:

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

Se il codice chiama B ref = (new A()).getB() in questa situazione l'oggetto new A() sarà disponibile per la garbage collection alcun riferimento ad esso esiste.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top