Java : 什么时候取消引用变量
Java : when is a variable de-referenced
希望获得 Java 遵循的一些幕后内存引用和规则。
这是一段代码。
基本上这个 class 用于实例化一些其他对象 (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 个被关闭的 "not working" 场景中,这是因为该变量是一个实例变量,并且当引用 doClose() 对象时,它使用恰好在 myOtherObject 中的引用执行 doClose() 时的变量?
基本上是在寻找 what/when 这些对象在幕后被取消引用,以及是否有针对该行为的官方术语。
你的困惑与取消引用无关,我不认为。我认为您的困惑是关于 闭包 。当你像你所做的那样创建一个匿名 class 实例时,你正在创建一个闭包,它会执行一些神奇的调用堆栈操作来获取局部变量的当前状态。让我们先看看您的工作示例。 (我已经删除了一些对这个解释没有必要的位)
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
时,您都在创建一个 new 局部变量。它可能与旧的名称相同,但您创建了一个新的局部变量。所以每个 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
;你只在一个对象上调用它。因此,在这种情况下,您要多次更改一个变量,然后创建几个新的 class 都指向这个变量。
匿名 classes 相对容易解构为 "real" classes。因此,如果闭包让您感到困惑,请尝试将每个代码片段转换为不使用匿名 classes 的形式(因此不要使用 new MyCustomObjectTracker() { ... }
,使用 [=22= 创建一个新文件]).这样做会让您考虑必须将什么状态传递给新对象,这是编译器在您创建匿名 class 实例时自动执行的操作。
希望获得 Java 遵循的一些幕后内存引用和规则。
这是一段代码。 基本上这个 class 用于实例化一些其他对象 (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 个被关闭的 "not working" 场景中,这是因为该变量是一个实例变量,并且当引用 doClose() 对象时,它使用恰好在 myOtherObject 中的引用执行 doClose() 时的变量?
基本上是在寻找 what/when 这些对象在幕后被取消引用,以及是否有针对该行为的官方术语。
你的困惑与取消引用无关,我不认为。我认为您的困惑是关于 闭包 。当你像你所做的那样创建一个匿名 class 实例时,你正在创建一个闭包,它会执行一些神奇的调用堆栈操作来获取局部变量的当前状态。让我们先看看您的工作示例。 (我已经删除了一些对这个解释没有必要的位)
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
时,您都在创建一个 new 局部变量。它可能与旧的名称相同,但您创建了一个新的局部变量。所以每个 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
;你只在一个对象上调用它。因此,在这种情况下,您要多次更改一个变量,然后创建几个新的 class 都指向这个变量。
匿名 classes 相对容易解构为 "real" classes。因此,如果闭包让您感到困惑,请尝试将每个代码片段转换为不使用匿名 classes 的形式(因此不要使用 new MyCustomObjectTracker() { ... }
,使用 [=22= 创建一个新文件]).这样做会让您考虑必须将什么状态传递给新对象,这是编译器在您创建匿名 class 实例时自动执行的操作。