数组赋值会产生NullPointerException

时间:2014-01-24 07:05:05

标签: java android arrays nullpointerexception

我在为数组赋值时遇到了问题,这个数组先前声明如下:

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
    }
}

3 个答案:

答案 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()中的任何代码接收控件之前调用。