Ссылка на вхождение объекта через анонимный класс-Java - PullRequest
6 голосов
/ 26 февраля 2011

Я читаю параллелизм 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);
    }
}

Из-за незавершенного построения escape-объекта Это выводит shal 62 62

Где, когда я изменил свой код следующим образом

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

Где как здесь. Это выводит shal 25 25

Я прав?Также есть ли какое-либо переупорядочение операций, потому что в первом примере возраст был инициализирован как 62. Даже если в моем втором примере поле escaper не было окончательным, это работает!

Ответы [ 2 ]

8 голосов
/ 27 февраля 2011

В первой форме объект прослушивателя событий регистрируется в источнике событий внутри конструктора , и, таким образом, он сам (и посредством ассоциации с объектом "this") становится доступным для источника события до Конструктор завершает. Если внутреннему объекту класса удаляется, то и внешнему объекту.

Почему это проблема? Как только слушатель события зарегистрирован, источник события может вызывать его методы в любое время. Представьте себе, что поток, который использует источник события, начинает вызывать методы прослушивателя событий. Теперь это может произойти даже до того, как конструктор завершит работу.

Эта проблема хуже, чем кажется, однако из-за проблем с видимостью. Даже если вы сделаете регистрацию "последней операцией", которую выполняет конструктор, все равно есть возможность увидеть частично построенный объект или объект в недопустимом состоянии. Просто нет гарантии видимости при отсутствии надлежащего события до заказа.

Объявление его окончательным дает то, что происходит до упорядочения (таким образом, вторая форма).

2 голосов
/ 27 февраля 2011

когда у вас есть внутренний класс, который не является статическим, как

class Outer {
    class Inner {
    }
}

внутренний класс имеет скрытое поле, которое ссылается на внешний класс, так что вы можете себе представить, что это так

class Outer {
    class Inner {
        Outer hiddenOuter;
    }
}

Таким образом, где бы ни использовался внутренний объект, внешний объект является ссылочным, и, таким образом, его время жизни, по крайней мере, равно внутреннему объекту.

...