我在为数组赋值时遇到了问题,这个数组先前声明如下:
Enemy[] enemies = new Enemy[100];
我还有另一个变量来定义产生的敌人数量:
int numEnemies = 0;
稍后,我(尝试)在触摸屏幕时动态地将此数组的成员分配给Enemy
个对象:
public void spawnEnemy() {
Enemy enemy = new Enemy(...);
... initialise enemy ...
enemies[numEnemies++] = enemy; // this line causes NPE
}
我有这个堆栈跟踪:
01-24 02:00:28.509: E/AndroidRuntime(1394): FATAL EXCEPTION: UpdateThread
01-24 02:00:28.509: E/AndroidRuntime(1394): Process: com.example.menutest, PID: 1394
01-24 02:00:28.509: E/AndroidRuntime(1394): java.lang.NullPointerException
01-24 02:00:28.509: E/AndroidRuntime(1394): at com.example.menutest.GameScene.spawnEnemy(GameScene.java:333)
01-24 02:00:28.509: E/AndroidRuntime(1394): at com.example.menutest.GameScene.initJoints(GameScene.java:325)
01-24 02:00:28.509: E/AndroidRuntime(1394): at com.example.menutest.GameScene.loadLevel(GameScene.java:189)
01-24 02:00:28.509: E/AndroidRuntime(1394): at com.example.menutest.GameScene.createScene(GameScene.java:80)
01-24 02:00:28.509: E/AndroidRuntime(1394): at com.example.menutest.BaseScene.<init>(BaseScene.java:24)
01-24 02:00:28.509: E/AndroidRuntime(1394): at com.example.menutest.GameScene.<init>(GameScene.java:32)
01-24 02:00:28.509: E/AndroidRuntime(1394): at com.example.menutest.SceneManager$1.onTimePassed(SceneManager.java:118)
01-24 02:00:28.509: E/AndroidRuntime(1394): at org.andengine.engine.handler.timer.TimerHandler.onUpdate(TimerHandler.java:94)
01-24 02:00:28.509: E/AndroidRuntime(1394): at org.andengine.engine.handler.UpdateHandlerList.onUpdate(UpdateHandlerList.java:47)
01-24 02:00:28.509: E/AndroidRuntime(1394): at org.andengine.engine.Engine.onUpdateUpdateHandlers(Engine.java:618)
01-24 02:00:28.509: E/AndroidRuntime(1394): at org.andengine.engine.Engine.onUpdate(Engine.java:605)
01-24 02:00:28.509: E/AndroidRuntime(1394): at org.andengine.engine.Engine.onTickUpdate(Engine.java:568)
01-24 02:00:28.509: E/AndroidRuntime(1394): at org.andengine.engine.Engine$UpdateThread.run(Engine.java:858)
编辑:
我的应用程序是用AndEngine编写的,因此从SceneManager中调用CreateScene()方法,我确信它可以完美地运行。
public class GameScene extends BaseScene {
Enemy enemies[] = new Enemy[100];
int numEnemies = 0;
public void createScene() {
ResourcesManager.getInstance().setGameScene(this);
this.setOnSceneTouchListener((IOnSceneTouchListener) ResourcesManager.mBaseGameActivity);
createBackground();
createHUD();
createPhysicsWorld();
// the above set up scene for later use
loadLevel(1);
}
public void loadLevel(int levelID) {
initJoints();
}
private void initJoints() {
mPlanet = new Planet(400, 225, ResourcesManager.getInstance().planet, mVertexBufferObjectManager, 500);
mPlanet.mBody = PhysicsFactory.createBoxBody(mPhysicsWorld, mPlanet, BodyType.StaticBody, FIXTURE_DEF);
mPlanet.mBody.setUserData(mPlanet);
this.attachChild(mPlanet);
mPhysicsWorld.registerPhysicsConnector(new PhysicsConnector(mPlanet, mPlanet.mBody, true, true));
float x1 = 200;
float y1 = 112;
mSatellite = SatelliteFactory.createSatellite(SatelliteType.BASIC, x1, y1, mVertexBufferObjectManager, mPlanet);
this.attachChild(mSatellite);
spawnEnemy(); // causes exception
}
private void spawnEnemy() {
float y = getRandomY();
float maxHealth = 100;
Enemy enemy = new Enemy(0, y, ResourcesManager.getInstance().satellite_no_image, ResourcesManager.mVertexBufferObjectManager, maxHealth);
enemy.mBody = PhysicsFactory.createBoxBody(mPhysicsWorld, enemy, BodyType.DynamicBody, FIXTURE_DEF);
this.attachChild(enemy);
enemy.mBody.setLinearVelocity(new Vector2((mPlanet.getX() - enemy.mBody.getPosition().x) / PhysicsConstants.PIXEL_TO_METER_RATIO_DEFAULT,
(mPlanet.getY() - enemy.mBody.getPosition().y) / PhysicsConstants.PIXEL_TO_METER_RATIO_DEFAULT));
enemy.mBody.setLinearVelocity(new Vector2(mPlanet.getX(), mPlanet.getY() - y));
mPhysicsWorld.registerPhysicsConnector(new PhysicsConnector(enemy, enemy.mBody, true, true));
enemies[numEnemies++] = enemy; // NPE
}
}
答案 0 :(得分:1)
请添加一个Log.d()并查看显示的内容:
Log.d("~~~","\n\n\n\n~~~ enemies="+enemies+" enemy="+enemy);
enemies[numEnemies++] = enemy; // this line causes NPE
我怀疑这是因为初始化的顺序,函数肯定是从构造函数或初始化程序中调用的。
还请注意日志中的以下内容:
at com.example.menutest.GameScene.initJoints(GameScene.java:325)
at com.example.menutest.GameScene.loadLevel(GameScene.java:189)
at com.example.menutest.GameScene.createScene(GameScene.java:80)
at com.example.menutest.BaseScene.<init>(BaseScene.java:24)
at com.example.menutest.GameScene.<init>(GameScene.java:32)
GameScene构造函数调用BaseScene构造函数,后者又调用GameScene方法 - 在GameScene实例创建完成之前。
另外,您写道:我(尝试)在触摸屏幕时动态地将此数组的成员分配给Enemy对象但是我发现代码是在超时时启动的:
at com.example.menutest.SceneManager$1.onTimePassed(SceneManager.java:118)
答案 1 :(得分:0)
好的,试试这个:就在您获得NPE的行之前,添加
if (enemy == null) System.out.println("enemy is null");
if (numEntries == null) System.out.println("numEntries is null");
if (enemies == null) System.out.println("enemies is null");
enemies[numEnemies++] = enemy; // NPE
这能为您提供有用的信息吗?
答案 2 :(得分:0)
我会解释会发生什么:
如何在调用实例构造函数之前调用实例方法?
class B {
B() {
m();
}
void m() {
System.out.println("B.m()");
}
}
class X extends B {
int x = 8;
void m() {
System.out.println("X.m() x="+x);
}
}
public class A {
public static void main(String[] p) {
X x = new X();
x.m();
}
}
让我们运行它:
$ javac A.java
$ java A
X.m() x=0
X.m() x=8
在C ++中不可能出现这种不当行为,其中 B.m()而不是 X.m()将从基类构造函数中调用。
在从构造函数 X()执行任何代码之前,会自动调用构造函数 B(),因此方法 Xm()在构造函数 X()中的任何代码接收控件之前调用。