在Java中设置对象为null和程序流



我想要一点帮助理解如何设置一个对象为null的工作在java中。我有一种情况,乍一看,似乎一个对象被设置为空,突然不是空的,但显然这是不可能的。

我有一个类,我在其中创建了一个对象。这个对象是一个场景。这是一个Open GL ES 2.0项目,所以这个场景的render()和updateLogic()方法是从onDrawFrame调用的(这是通过场景管理器控制的,所以我们可以很容易地切换场景)。

所以,我可能会有这样的东西(为了这个问题的目的而减少代码):
public class MyGLRenderer implements GLSurfaceView.Renderer{
    MyScene myScene;
    SomeOtherScene someOtherScene;
    public void createScenes(){
        myScene = new MyScene(this);
        someOtherScene = new SomeOtherScene(this);
        SceneManager.getInstance().setCurrentScene(myScene);
    }
    public void cleanUp(){
        myScene = null;
        Log.v("tag","myScene (from MyGLRenderer) is: "+myScene);
        SceneManager.getInstance().setCurrentScene(someOtherScene);   //Scene changed but this won't take effect until the next 'tick'   
    } 
    @Override
    public void onDrawFrame(GL10 gl) {
        SceneManager.getInstance().getCurrentScene().updateLogic();
        SceneManager.getInstance().getCurrentScene().render();
    }
}
在上述情况下,处理被移交给myScene,它看起来像这样:
public class MyScene implements Scene{
    MyGLRenderer renderer;
    public myScene(MyGLRenderer renderer){     
        this.renderer = renderer;
    }
    @Override
    public void render(){
        //Render something here
    }
    @Override
    public void updateLogic(){
        doSomething();           
        //The condition here could be anything - maybe the user taps the sceen and a flag is set in onTouchEvent for example
        if (someConditionIsMet){
            renderer.cleanup();
        }            
         Log.v("tag","myScene (from within myScene) is: "+this);
    }
}

所以,当我使用场景管理器设置场景时,处理被转移到那个场景,它的updateLogic和渲染方法从onDrawFrame中不断被调用。

当我运行我的代码时,我很惊讶它没有因为NullpointerException而崩溃。日志是这样的:

myScene (from within myScene) is: com.program.name.MyScene@26354632
myScene (from within myScene) is: com.program.name.MyScene@26354632
myScene (from within myScene) is: com.program.name.MyScene@26354632
myScene (from within myScene) is: com.program.name.MyScene@26354632
myScene (from within myScene) is: com.program.name.MyScene@26354632
myScene (from within myScene) is: com.program.name.MyScene@26354632
myScene (from within myScene) is: com.program.name.MyScene@26354632
myScene (from within myScene) is: com.program.name.MyScene@26354632
myScene (from MyGLRenderer) is: null
myScene (from within myScene) is: com.program.name.MyScene@26354632

正如你所看到的,'myScene'是有效的,直到cleanUp()方法被调用并将其设置为null。但代码然后返回到myScene完成,它仍然是有效的(不是null)。

我真的很想了解事情是如何在Java中工作的-为什么它似乎一分钟为空(或从一个地方),然后不是(从不同的地方)?

你只是在renderer中清除了对MyScene的引用,但是对象仍然在那里,SceneManager可能仍然持有它。

混乱似乎是关于"设置一个对象为null"。这是不可能的。您只能将指向对象的变量设置为null。在此之后,变量指向null,但对象可能仍然存在(就像您的情况一样)。

具体来说,你在这里把它交给场景经理:

SceneManager.getInstance().setCurrentScene(myScene);

对象只有在没有保存对它的引用时才会被垃圾收集。在您的情况下,这可能是场景更改生效的时候。

看起来你遇到了一个线程安全错误。

其他线程可以看到变量的陈旧值,除非你"安全发布"值的变化。(你有一个CPU改变其缓存行的值,但另一个CPU仍然看到陈旧的缓存数据-你需要强制缓存写入主存,但这是昂贵的,所以Java不会这样做,直到它被告知)。

根据您的确切需求,有许多安全发布值的方法。看看你的代码,似乎所有你需要做的是声明myScene字段是易变的。它可能也应该是私人的。所以尝试:

private volatile Scene myScene;

如果你想正确理解Java中的线程安全,那么我强烈推荐"the Train Book":http://www.amazon.com/Java-Concurrency-Practice-Brian-Goetz/dp/0321349601

相关内容

  • 没有找到相关文章

最新更新