2013-05-17 9 views
10

は、私は次のコードを持っている:外部クラスのコンストラクタで匿名クラスをインスタンス化できますか?

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

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

をしかし、私の友人はそれでいくつかの問題があることを教えてくれました。私はOuterのコンストラクタに匿名クラスインスタンスを作成したので、匿名クラスインスタンスはOuterクラスインスタンス、つまりOuter.thisを暗黙的に参照しています。しかし、現時点では、Outerクラスのインスタンスはまだ完全には作成されていません。したがって、匿名クラスインスタンスは、不完全な状態のオブジェクトを参照します。したがって、問題です。

彼は正しいですか?ありがとう。

+0

Anonyはインターフェイスであり、クラスではありません! – zEro

+3

はい、新しいAnony(){...}は匿名クラスインスタンスを作成しました。右。 – Kai

+0

@zEroはい、 'Anony'はインターフェースですが、インターフェースを実装する匿名クラスのインスタンスを作成するための構文です。同じ構文は、別のクラスを拡張する匿名クラスのインスタンスをインスタンス化するときに使用されます。 – jpmc26

答えて

3

友人は正しいですが、もちろん使い方によって異なります。

問題は、コンストラクタ内で内部クラスを作成することではありません。問題は、内部クラスが外部クラスにアクセスする場合に発生します。

これは、どのオブジェクトでもコンストラクタ内に正規の権限付与対象を与えることができないためです。オブジェクト操作に必要なすべての変数が初期化されていない可能性があります。

しかし、内部クラスがコンストラクタの最後に置かれている場合は、この問題は発生しませんが、これは危険な策略私は、私は考えることができるすべての異なる可能性のbrainf..k例建て誰かがコードを変更することができ、それがデバッガでWTFの時間だ...

0

ため:予想

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

を出力は:

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

あなたはです。ですが、そうしないでください。

これは、「コンストラクタからの参照エスケープ」と様々に知られているアンチパターンの例です。コンストラクタ内から別のクラスに参照を渡しています。マルチスレッド環境では、参照が渡されたクラスがの部分的にの新しいオブジェクトを表示することがあるため、が一致しないの状態になることがあります。これは奇妙で難しいバグにつながる可能性があります。このIBMのarticleは、多くの記述の1つです。明らかではない何

どのようそれはここに起こっている:匿名クラスは、実際にインナークラスですので、彼らが含んでいるクラスへの参照を保持する(すなわちthisが構築されています)。受領者クラスOtherClassは、建設が完了する前にthisを見ても、それに従うことさえあります。

関連する問題