我知道这this = null
是非法的。
我想知道是否有其他方法可以让对象自行清理。
我的愿望是能够做这样的事情:
A a = new A();
a.doStuffAndDisappear();
if(a == null){
//this is true after my doStuffAndDisappear() method.
}
我怀疑没有办法做到这一点,但认为这值得一问。
我知道这this = null
是非法的。
我想知道是否有其他方法可以让对象自行清理。
我的愿望是能够做这样的事情:
A a = new A();
a.doStuffAndDisappear();
if(a == null){
//this is true after my doStuffAndDisappear() method.
}
我怀疑没有办法做到这一点,但认为这值得一问。
不,因为a
是一个引用(不是这个问题标题中的对象),除了定义引用的方法(我从代码上下文中假设它a
是一个局部变量)之外,没有任何方法可以修改引用的值。
由于 Java 没有按引用传递,因此您所要求的无法完成:无法收集引用地址以管理指向的地址。您可能会使用包装器对象,但不确定有什么意义。
正如其他人所说,这根本不可能。如果它正在清理您所追求的资源,那么您可能会考虑使用以下模式:
class A {
private boolean cleanedUp;
public void cleanUp() {
// clean up any resources
cleanedUp = true;
}
public boolean isCleanedUp() {
return cleanedUp;
}
}
然后像这样使用它:
A a = new A();
a.cleanUp();
if (a.isCleanedUp()) {
...
}
更好的解决方案可能是根据您的情况实现java.io.Closeable
or接口:java.lang.AutoCloseable
class B implements AutoCloseable {
private boolean closed;
public boolean isClosed() {
return closed;
}
@Override public void close() throws Exception {
// clean up any resources
closed = true;
}
}
在这种情况下,您可以使用 try-with-resources 语句:
try (B b = new B()) {
// do stuff
} catch (Exception ex) {
// oh crap...
}
或者您甚至可以将两者结合起来并按照您喜欢的方式进行操作。
或者最后你可以按照威廉·莫里森解释的方式来做(虽然我可能会作弊并只是使用java.util.concurrent.atomic.AtomicReference
而不是创建我自己的类,并且它具有成为通用类型的额外好处),这取决于你的情况,可能真的是不必要的。毕竟,你总是可以这样做(即使它看起来有点奇怪):
A a = new A();
a.doStuffAndDisappear();
a = null;
if(a == null){
//...
}
我可能遗漏了一些东西,但是,既然你提到了:
我想知道是否有其他方法可以让对象自行清理。
和:
我有一个自包含的小部件,如果它可以在完成它需要做的事情后使自己为空,它将得到很大的改进。因此让 GC 清理它,而不是让 Widget 的用户不得不手动将其设置为 null。
怎么样,根本不保留对对象的引用?
new A().doStuffAndDisappear();
// no reference, instance of A is eligible to GC
更新
由于这不是 OP 正在寻找的,让我扩展@Perce 解决方案:
interface AHolder
{
void setA(A a);
}
class AParent implements AHolder {
private A a;
public AParent() {
a = new A();
}
public void doSomething() {
a.doStuffAndDisappear(this);
if(a == null)
{
System.out.println("It is true!");
}
}
public void setA(A a) {
this.a = a;
}
}
class A
{
void doStuffAndDisappear(AHolder parent) {
parent.setA(null);
}
}
现在您不需要知道 parent 的类型或包含A
.
工作示例。
如果你想A
在每个父节点上都引用 null ,只需更改A
为保存父列表 ( List<AParent> parents
),并实现一个方法来跟踪父节点:
void addParent(AParent parent)
{
parents.add(parent);
}
加上一个void cleanUp()
迭代其父母设置为null的:
void cleanUp()
{
for (AParent parent : parents)
{
parent.setA(null);
}
parents.clear();
}
注意这个解决方案看起来很像 JavaBeans Bound Properties ... 这不是巧合;在某种程度上,我们正在创建一个简单的事件/监听器架构,它A
可以通知它的父母来获取他们对它的引用。
是的,如果您在应用程序中重新实现 GC,这是可能的。我的回答受到您与 Patricia 讨论的启发,您说您希望将对该对象的所有引用设置为 null。GC 示例:
class MyGC {
byte[100000] myMemory;
int nextFreeCell;
myNew (int value) { }
get (int myCell) { }
}
这样,您可以控制没有其他对您的类的引用。您的类还必须仅包含对您的 GC 内存的引用。你的例子:
int cell = MyGC.new(A.class)
MyGC.get(cell).doSomething();
if (MyGC.get(cell) == null)
--- true -----
这个巧妙的问题在技术上很有趣。但是,考虑到您的意图:您正在尝试强制所有引用的条件为,null
以便您可以防止对其他过期实例的无效使用。
给 .赋予任何含义都是不好的做法null
。
相反,修改(或外观,如果你不能修改)你的A
对象,以便其他一些标志可用。例如public boolean isClosed() ...
这是不可能的,我想。如果a
是某个对象的实例变量x
,则doStuffAndDisappear
可以以某种方式获取对的引用x
并调用 setter 将其设置a
为 null。最好不要走那条路,因为它完全违反直觉。
最好的办法是清理doStuffAndDisappear
(好吧,不能消失)并确保没有其他人指的是a
. GC应该注意休息。
你不能让一个对象像这样将另一个对象的引用设置为 null ,而不让它们都知道彼此。没有一些跑腿就不可能做你想做的事。我建议不要使用以下示例。
public class A{
A other;
public A(A a){
this.other = a;
if(a!=null)
a.other = this;
}
public void doSomethingAndDisappear(){
a.other = null;
}
}
这将导致一个值对第二个引用的引用消失,因为第二个引用将第一个引用的引用设置为 null。