希望获得一些幕后的内存引用和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()?
基本上寻找什么/什么时候这些对象在幕后被取消引用,以及是否有行为的官方术语。
你的困惑不是解除引用,我不这么认为。我认为你的困惑是关闭。当你创建一个像你已经完成的匿名类实例时,你正在创建一个闭包,它会执行一些神奇的调用堆栈来获取局部变量的当前状态。让我们先看看你的工作实例。 (我已经删除了一些对此解释不必要的位)
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
)。以这种方式执行此操作将使您考虑必须将状态传递给新对象,这是编译器在创建匿名类实例时自动执行的操作。