Java:何时是一个被引用的变量

问题描述 投票:1回答:1

希望获得一些幕后的内存引用和Java遵循的规则。

这是一段代码。基本上这个类用于实例化一些其他对象(MyOtherObject),之后对此对象的引用将doClose()方法发送到Vector。

如果创建了3个MyOtherObject对象,则Vector将有3个条目。

最终将调用一个进程,使Listener迭代MyOtherObject对象的Vector并为每个对象调用doClose()。

目前代码显示

 myOtherObject = new myOtherObject();

作为活动线。使用此行时,实际上只会关闭3个MyOtherObject对象中的1个。

如果代码更改为

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

由于“working”中的变量是本地的,并且以后不可用于引用,Java在变量超出范围时是否将变量替换为实际的对象引用?

在只有1被关闭的“不工作”场景中,这是因为变量是一个实例变量,并且在对doClose()对象的引用时,它使用在执行时恰好在myOtherObject变量中引用的内容对于doClose()?

基本上寻找什么/什么时候这些对象在幕后被取消引用,以及是否有行为的官方术语。

java memory dereference
1个回答
1
投票

你的困惑不是解除引用,我不这么认为。我认为你的困惑是关闭。当你创建一个像你已经完成的匿名类实例时,你正在创建一个闭包,它会执行一些神奇的调用堆栈来获取局部变量的当前状态。让我们先看看你的工作实例。 (我已经删除了一些对此解释不必要的位)

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)。以这种方式执行此操作将使您考虑必须将状态传递给新对象,这是编译器在创建匿名类实例时自动执行的操作。

© www.soinside.com 2019 - 2024. All rights reserved.