将对象设置为 null 并在 Java 中执行程序流程
Setting object to null and program flow in Java
我需要一些帮助来理解如何在 java 中将对象设置为 null。我有这样一种情况,乍一看似乎设置为 null 的对象突然不为 null,但显然情况并非如此。
我有一个 class,我在其中创建了一个对象。这个对象是一个场景。这是一个 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
如您所见,在调用 cleanUp() 方法并将其设置为 null 之前,'myScene' 一直有效。但是代码然后 returns 到 myScene 完成,它仍然有效(不为空)。
我真的很想了解 Java 中的工作原理 - 为什么 似乎 一分钟(或从一个地方)为空,然后又没有(来自不同的地方)?
您只是在渲染器中清除了对 MyScene 的引用,但该对象仍然存在并且 SceneManager 可能仍然保留着它。
混淆似乎与 "setting an object to null" 有关。这真的不可能。您只能将指向对象的变量设置为空。此后,变量指向 null,但对象可能仍然存在(如您的情况)。
具体你这里交给现场管理员:
SceneManager.getInstance().setCurrentScene(myScene);
只有在没有任何对象持有对它的引用时,该对象才会被垃圾回收。在您的情况下,这可能是场景更改生效的时间。
看起来您 运行 遇到了线程安全错误。
其他线程可以看到变量的陈旧值,除非您 "safely publish" 更改值。 (你有一个 CPU 在它的缓存行中改变了一个值,但是另一个 CPU 仍然看到陈旧的缓存数据 - 你需要强制缓存写入主内存但是这是昂贵的所以 Java 在被告知之前不会这样做)。
有很多方法可以根据您的具体要求安全地发布值。查看您的代码,似乎您需要做的就是将 myScene 字段声明为易变的。它可能也应该是私人的。所以尝试:
private volatile Scene myScene;
如果你想正确理解Java中的线程安全,那么我强烈推荐"the Train Book":http://www.amazon.com/Java-Concurrency-Practice-Brian-Goetz/dp/0321349601
我需要一些帮助来理解如何在 java 中将对象设置为 null。我有这样一种情况,乍一看似乎设置为 null 的对象突然不为 null,但显然情况并非如此。
我有一个 class,我在其中创建了一个对象。这个对象是一个场景。这是一个 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
如您所见,在调用 cleanUp() 方法并将其设置为 null 之前,'myScene' 一直有效。但是代码然后 returns 到 myScene 完成,它仍然有效(不为空)。
我真的很想了解 Java 中的工作原理 - 为什么 似乎 一分钟(或从一个地方)为空,然后又没有(来自不同的地方)?
您只是在渲染器中清除了对 MyScene 的引用,但该对象仍然存在并且 SceneManager 可能仍然保留着它。
混淆似乎与 "setting an object to null" 有关。这真的不可能。您只能将指向对象的变量设置为空。此后,变量指向 null,但对象可能仍然存在(如您的情况)。
具体你这里交给现场管理员:
SceneManager.getInstance().setCurrentScene(myScene);
只有在没有任何对象持有对它的引用时,该对象才会被垃圾回收。在您的情况下,这可能是场景更改生效的时间。
看起来您 运行 遇到了线程安全错误。
其他线程可以看到变量的陈旧值,除非您 "safely publish" 更改值。 (你有一个 CPU 在它的缓存行中改变了一个值,但是另一个 CPU 仍然看到陈旧的缓存数据 - 你需要强制缓存写入主内存但是这是昂贵的所以 Java 在被告知之前不会这样做)。
有很多方法可以根据您的具体要求安全地发布值。查看您的代码,似乎您需要做的就是将 myScene 字段声明为易变的。它可能也应该是私人的。所以尝试:
private volatile Scene myScene;
如果你想正确理解Java中的线程安全,那么我强烈推荐"the Train Book":http://www.amazon.com/Java-Concurrency-Practice-Brian-Goetz/dp/0321349601