Java: когда переменная разыменована - PullRequest
1 голос
/ 28 марта 2019

Нужны некоторые закулисные ссылки на память и правила, которым следует Java.

Вот фрагмент кода. По сути, этот класс используется для создания экземпляра какого-либо другого объекта (MyOtherObject), после чего ссылка на этот объект doClose () отправляется в Vector.

Если создано 3 объекта MyOtherObject, вектор будет иметь 3 записи.

В конечном итоге будет вызван процесс, заставляющий прослушиватель перебирать объекты Vector объектов MyOtherObject и вызывать doClose () для каждого из них.

В настоящее время код показывает

 myOtherObject = new myOtherObject();

в качестве активной строки. Когда эта строка используется, только 1 из 3 объектов MyOtherObject будет фактически закрыт.

Если код изменен на

   MyOtherObject myOtherObject = new MyOtherObject();

тогда каждый из 3 объектов MyOtherObject получит свою процедуру doClose ().

public class MyObject
{
    MyOtherObject myOtherObject ;

     public static MyObject getInstance()
     {
            :
            :
            :
         return instance;
     }

    public void runThis () 
    {

        ///MyOtherObject myOtherObject = new MyOtherObject(); //Works

        myOtherObject = new myOtherObject();  //Only closes one

        MyCustomObjectTracker customObjectTracker = new MyCustomObjectTracker()
                {
                    @Override
                    public void closingMyWindows()
                    {
                            myOtherObject.doClose();
                    }
                };

        refernceToSomeOtherObject.addMyObjectTracker(customObjectTracker);
    }
}

Поскольку переменная в «рабочем» является локальной и не будет доступна для справки в будущем, заменяет ли Java переменную на реальную ссылку на объект в тот момент, когда переменная выходит из области видимости?

В сценарии «не работает», когда закрывается только 1, это происходит потому, что переменная является переменной экземпляра, а когда создается ссылка на объект doClose (), она использует то, что когда-либо ссылается на переменную myOtherObject в время выполнения для doClose ()?

В основном, ищет, что / когда эти объекты разыменовываются за кулисами, и есть ли официальная терминология для поведения.

1 Ответ

1 голос
/ 28 марта 2019

Твоя путаница не в разыменовании, я не думаю.Я думаю, что ваше замешательство связано с закрытием .Когда вы создаете экземпляр анонимного класса, как вы сделали, вы делаете замыкание, которое выполняет магический вызов стека, чтобы получить текущее состояние локальных переменных.Давайте сначала посмотрим на ваш рабочий пример.(Я удалил некоторые биты, которые не нужны для этого объяснения)

public class MyObject {
    public void runThis() {
        MyOtherObject myOtherObject = new MyOtherObject();
        MyCustomObjectTracker customObjectTracker = new MyCustomObjectTracker() {
            @Override
            public void closingMyWindows() {
                myOtherObject.doClose();
            }
        };
    }
}

Когда вы делаете new MyCustomObjectTracker() { ... }, компилятор Java видит, что вы используете переменную myOtherObject, поэтому он неявно закрывается вокруг этогопеременная, вспоминая это на потом.Обратите внимание, что здесь важно то, что каждый раз, когда вы вызываете runThis, вы создаете новую локальную переменную.Может иметь то же имя, что и старое, но вы создали новую локальную переменную.Таким образом, каждый customObjectTracker получает доступ к другой локальной переменной.Следовательно, все работает.Теперь давайте посмотрим на другой пример.

public class MyObject {
    MyOtherObject myOtherObject;
    public void runThis() {
        myOtherObject = new MyOtherObject();
        MyCustomObjectTracker customObjectTracker = new MyCustomObjectTracker() {
            @Override
            public void closingMyWindows() {
                myOtherObject.doClose();
            }
        };
    }
}

Здесь код проходит то же самое обоснование.Нам нужно закрыть то, что называется myOtherObject.Но myOtherObject не является локальной переменной;это переменная экземпляра.Так что на самом деле нам нужно закрыть объект, которому он принадлежит, что составляет this.Обратите внимание, что есть только один this.Вы можете позвонить runThis несколько раз;Вы вызываете это только на одном объекте.Поэтому в этом случае вы меняете одну переменную несколько раз, а затем создаете несколько новых классов, которые все указывают на эту одну переменную.

Анонимные классы относительно легко разложить на «реальные» классы вручную.Поэтому, если замыкания сбивают вас с толку, попробуйте преобразовать каждый из ваших фрагментов кода в форму, в которой не используются анонимные классы (поэтому вместо new MyCustomObjectTracker() { ... } создайте новый файл с class MySpecialCustomObjectTracker extends MyCustomObjectTracker).Поступая таким образом, вы будете думать о том, какое состояние должно быть передано вашему новому объекту, что и делает компилятор автоматически при создании экземпляра анонимного класса.

...