17

我知道这this = null是非法的。

我想知道是否有其他方法可以让对象自行清理。

我的愿望是能够做这样的事情:

A a = new A();

a.doStuffAndDisappear();

if(a == null){
     //this is true after my doStuffAndDisappear() method.
}

我怀疑没有办法做到这一点,但认为这值得一问。

4

7 回答 7

16

不,因为a是一个引用(不是这个问题标题中的对象),除了定义引用的方法(我从代码上下文中假设它a是一个局部变量)之外,没有任何方法可以修改引用的值。

由于 Java 没有按引用传递,因此您所要求的无法完成:无法收集引用地址以管理指向的地址。您可能会使用包装器对象,但不确定有什么意义。

于 2013-08-17T21:51:38.377 回答
5

正如其他人所说,这根本不可能。如果它正在清理您所追求的资源,那么您可能会考虑使用以下模式:

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.Closeableor接口: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){
     //...
}
于 2013-08-17T22:06:14.957 回答
2

我可能遗漏了一些东西,但是,既然你提到了:

我想知道是否有其他方法可以让对象自行清理。

和:

我有一个自包含的小部件,如果它可以在完成它需要做的事情后使自己为空,它将得到很大的改进。因此让 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可以通知它的父母来获取他们对它的引用。

于 2013-08-17T23:16:00.267 回答
2

是的,如果您在应用程序中重新实现 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 -----
于 2013-08-17T23:45:28.380 回答
2

这个巧妙的问题在技术上很有趣。但是,考虑到您的意图:您正在尝试强制所有引用的条件为,null以便您可以防止对其他过期实例的无效使用。

给 .赋予任何含义都是不好的做法null

相反,修改(或外观,如果你不能修改)你的A对象,以便其他一些标志可用。例如public boolean isClosed() ...

于 2013-08-18T00:04:39.527 回答
1

这是不可能的,我想。如果a是某个对象的实例变量x,则doStuffAndDisappear可以以某种方式获取对的引用x并调用 setter 将其设置a为 null。最好不要走那条路,因为它完全违反直觉。

最好的办法是清理doStuffAndDisappear(好吧,不能消失)并确保没有其他人指的是a. GC应该注意休息。

于 2013-08-17T21:58:49.737 回答
0

你不能让一个对象像这样将另一个对象的引用设置为 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。

于 2013-08-17T21:54:44.233 回答