2013-05-17 19 views
10

Ho il codice seguente:Posso creare un'istanza di una classe anonima nel costruttore della classe esterna?

public class Outer { 
    public Interface Anony { 
     public void callback(); 
    } 

    public Outer() { 
     OtherClass.foo(new Anony() { 
      @Override 
      public void callback() { 
       .... 
      } 
     }); 
    } 
} 

Ma il mio amico mi ha detto che c'è qualche problema in esso. Ho creato un'istanza di classe anonima nel costruttore di Outer, quindi l'istanza di classe anonima fa riferimento implicitamente all'istanza di classe Outer, ad esempio Outer.this. Ma in questo momento, l'istanza della classe Outer non è stata ancora completamente creata. Quindi l'istanza di classe anonima fa riferimento a un oggetto con stati incompleti, quindi il problema.

Ha ragione? Grazie.

+0

Anony è un'interfaccia, non una classe! – zEro

+3

sì, ma il nuovo Anony() {...} ha creato un'istanza di classe anonima. Destra. – Kai

+0

@zEro Sì, 'Anony' è un'interfaccia, ma questa è la sintassi per la creazione di istanze di classi anonime che implementano un'interfaccia. La stessa sintassi viene utilizzata quando si istanziano istanze di classi anonime che estendono un'altra classe. – jpmc26

risposta

3

L'amico ha ragione, ma dipende ovviamente dall'utilizzo.

Il problema non consiste nel creare la classe interna all'interno del costruttore. Il problema si verificherà SE la classe interna accede alla classe esterna.

Questo perché qualsiasi oggetto non sarà in grado di fornire normali beneficiari all'interno di un costruttore. Tutte le variabili necessarie per le operazioni degli oggetti potrebbero non essere state inizializzate, ecc.

Tuttavia, se la classe interna viene posta alla fine del costruttore, non vedo questo problema, ma tenere presente che questo è un mossa pericolosa perché qualcuno può modificare il codice e poi è il momento WTF con il debugger ...

0

ho costruito un esempio brainf..k di tutte le diverse possibilità mi veniva in mente:

class OtherClass 
{ 
    public static void foo (final Anony x) 
    { 
    x.callback(); 
    } 
} 

public class Outer 
{ 
    public interface Anony 
    { 
    void callback(); 
    } 

    public class Inner implements Anony 
    { 
    public void callback() 
    { 
     System.out.println ("Inner.callback"); 
    } 
    } 

    public class InnerDerived implements Anony 
    { 
    public void callback() 
    { 
     System.out.println ("InnerDerived.callback"); 
    } 
    } 

    public static class StaticInner implements Anony 
    { 
    public void callback() 
    { 
     System.out.println ("StaticInner.callback"); 
    } 
    } 

    public Outer() 
    { 
    OtherClass.foo (new Anony() 
    { 
     public void callback() 
     { 
     System.out.println ("Anony.callback"); 
     } 
    }); 
    OtherClass.foo (new Inner()); 
    OtherClass.foo (new Inner() 
    { 
     @Override 
     public void callback() 
     { 
     System.out.println ("Anony.Inner.callback"); 
     } 
    }); 
    OtherClass.foo (new InnerDerived()); 
    OtherClass.foo (new InnerDerived() 
    { 
     @Override 
     public void callback() 
     { 
     System.out.println ("Anony.InnerDerived.callback"); 
     } 
    }); 
    OtherClass.foo (new StaticInner()); 
    OtherClass.foo (new StaticInner() 
    { 
     @Override 
     public void callback() 
     { 
     System.out.println ("Anony.StaticInner.callback"); 
     } 
    }); 
    } 
} 

l'atteso l'output dovrebbe essere:

Anony.callback 
Inner.callback 
Anony.Inner.callback 
InnerDerived.callback 
Anony.InnerDerived.callback 
StaticInner.callback 
Anony.StaticInner.callback 
1

È può farlo, ma non si dovrebbe.

Questo è un esempio dell'anti-pattern noto in vari modi come "locazione di this escape dal costruttore" - passando un riferimento all'oggetto che viene costruito in un'altra classe dal costruttore. Il motivo non si dovrebbe fare questo è che in un ambiente multi-thread, la classe a cui è stato trasmesso il riferimento può vedere il nuovo oggetto in una parzialmente costruito, e quindi incoerente stato. Questo può portare a bug strani e difficili da trovare. Questo article di IBM è uno dei tanti che lo descrive.

Ciò che non è ovvio è come sta accadendo qui: classi anonime sono in realtà interni classi, in modo da mantenere un riferimento alla classe che contiene (cioè this fase di costruzione). La classe destinatario OtherClass potrebbe vedere, e persino agire su, this prima che la costruzione sia completata.

Problemi correlati