6

私は実際にJavaの並行性を読んでおり、以下の例はそれからのものです。そして、私の質問は、この参照エスケープとはどういう意味ですか?何が問題になりますか?。この参照はdoSomething(e)からどのようにエスケープしますか。

public class ThisEscape {
    public ThisEscape(EventSource source) {
        source.registerListener(
            new EventListener() {
                public void onEvent(Event e) {
                    doSomething(e);
                }
            }
        );
    }
}

これはどのように問題を解決しますか

public class SafeListener {
    private final EventListener listener;
    private SafeListener() {
        listener = new EventListener() {
            public void onEvent(Event e) {
                doSomething(e);
            }
        };
    }
    public static SafeListener newInstance(EventSource source) {
        SafeListener safe = new SafeListener();
        source.registerListener(safe.listener);
        return safe;
    }
}

編集 :

私は以下の例を試しました

public class Escape {
    public  Escape( Printer printer ){
        printer.print(new Escaper(){
            @Override
            public void parentData(){
            theCulprit1(Escape.this);
            }
            public String name = "shal";
            @Override
            public void theCulprit(){
            System.out.println( this.name );
            System.out.println( Escape.this.age );
            }
        });
        canAccess();
    }
    public void  canAccess(){
    this.age = "25";
    }
    public String age = "62";
    @SuppressWarnings("unused")
    public static void main(String args[]){
    Escape escape = new Escape(new Printer());
    }
}

class Printer{
    public void print(Escaper escaper){
    escaper.theCulprit();
    escaper.parentData();
    }
}

class Escaper{
    public void parentData(){
    }
    public void theCulprit(){
    }
    public void theCulprit1(Escape escape){
    System.out.println(escape.age);
    }
}

エスケープオブジェクトの構築が不完全なため、この出力はshal6262です。

このようにコードを変更したところ

public class Escape {
    private final Escaper escaper;
    private Escape( ){
        escaper = new Escaper(){
            @Override
            public void parentData(){
            theCulprit1(Escape.this);
            }
            public String name = "shal";
            public void theCulprit(){
            System.out.println( name );
            System.out.println( age );
            }
        };
        canAccess();
    }
    public void  canAccess(){
    age = "25";
    }
    public String age = "62";
    public static Escape newInstance( Printer printer){
    Escape escape = new Escape();
    printer.print(escape.escaper);
    return escape;
    }
    @SuppressWarnings("unused")
    public static void main(String args[]){
    Escape.newInstance(new Printer());
    }
}

ここのように。それはshal2525を出力します

私は正しいですか?また、最初の例では年齢が62に初期化されたため、操作の並べ替えもあります。2番目の例では、エスケープフィールドをfinalにしない場合でも、機能します。

4

2 に答える 2

8

最初の形式では、イベントリスナーオブジェクトはコンストラクター内のイベントソースに登録されるため、コンストラクターが完了する前に、それ自体(および関連付けによって「this」オブジェクト)をイベントソースで使用できるようになります。内部クラスオブジェクトがエスケープされると、外部オブジェクトもエスケープされます。

なぜこれが問題なのですか?イベントリスナーが登録されると、イベントソースはいつでもそのメソッドを呼び出すことができます。イベントソースが使用しているスレッドがイベントリスナーメソッドの呼び出しを開始するとします。これは、コンストラクターが完了する前でも発生する可能性があります。

ただし、この問題は、可視性の問題により、見た目よりも深刻です。登録をコンストラクターが行う「最後の操作」にしたとしても、部分的に構築されたオブジェクトまたは無効な状態のオブジェクトが表示される可能性があります。注文前に適切な事態が発生しない限り、可視性の保証はありません。

それを最終的に宣言することで、注文する前にそれが起こります(したがって2番目の形式)。

于 2011-02-26T22:39:49.543 に答える
2

静的ではない内部クラスがあるときはいつでも

class Outer {
    class Inner {
    }
}

内側のクラスには外側のクラスを参照する隠しフィールドがあるので、次のように想像できます。

class Outer {
    class Inner {
        Outer hiddenOuter;
    }
}

したがって、内側のオブジェクトが使用される場合は常に、外側のオブジェクトは参照可能であり、したがって、その存続期間は少なくとも内側のオブジェクトと同じ長さです。

于 2011-02-26T21:57:53.003 に答える