2015-09-07 78 views
0

我想要了解如何将对象设置为null在java中工作。我有一种情况,似乎乍一看似乎是一个设置为空的对象突然不是空的,但显然情况并非如此。在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: [email protected] 
myScene (from within myScene) is: [email protected] 
myScene (from within myScene) is: [email protected] 
myScene (from within myScene) is: [email protected] 
myScene (from within myScene) is: [email protected] 
myScene (from within myScene) is: [email protected] 
myScene (from within myScene) is: [email protected] 
myScene (from within myScene) is: [email protected] 
myScene (from MyGLRenderer) is: null 
myScene (from within myScene) is: [email protected] 

正如你所看到的,“myScene”是直到清理()方法被调用有效期,并将其设置为null。但代码然后返回myScene结束,它仍然有效(不为空)。

我真的很想了解Java在Java中的工作原理 - 为什么它似乎在一分钟内(或从一个地方)变为null,然后不是(从不同的地方)?

回答

1

您只需在渲染器中清除对MyScene的引用,但对象仍然存在,并且SceneManager可能仍然保留。

混淆似乎是关于“将对象设置为null”。这不是真的可能。您只能将指向对象的变量设置为null。在此之后,变量指向null,但对象可能仍然在那里(就像你的情况一样)。

Specificially,你把它交给这里的现场经理:

SceneManager.getInstance().setCurrentScene(myScene); 

的对象会得到垃圾回收仅如果没有持有对它的引用。就你而言,这可能是在场景更改生效时。

+0

感谢@StefanHaustein,OK那种有道理。我可能误解了一些事情。因此,因为'对象'仍在使用中(它仍然调用render()和updateLogic()方法),所以它不能GC'd,因此它一直保持活动状态,直到操作系统认为它是'自由的' - 即使当它被分配给它时的实际引用现在为null(并且没有其他实际的'引用'存在,即像this.myScene = myScene在其他某个类中的某处)? – Zippy

+0

我觉得现场经理仍然坚持下去,据此澄清我的回答。 –

+1

Theres仍然是对象的引用,因为调用堆栈必须从对象上的实例方法返回。另外,正如斯蒂芬所说,对象是零,渲染器的参考是。 –

0

看起来像你遇到了线程安全漏洞。

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

根据您的确切要求,有多种方法可以安全地发布值。看看你的代码,看起来你所需要做的就是将myScene字段声明为volatile。它可能应该是私人的。因此,尝试:

private volatile Scene myScene; 

如果要正确地理解在Java线程安全的,那么我强烈推荐“火车书”:http://www.amazon.com/Java-Concurrency-Practice-Brian-Goetz/dp/0321349601

+0

我试图让它变得不稳定,但我得到了同样的结果 - 没有崩溃,它运行完美。这可能是一个线程安全问题吗?我的意思是我在同一个线程(GL渲染线程)上运行,然后调用cleanUp();方法也来自同一个线程.... – Zippy

相关问题