2015-09-07 26 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

相關問題