2014-01-24 2 views
0

Я испытываю проблемы при присвоении значения массива, который ранее заявленной как так:Присваивание массива производит 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) 

EDIT:

Мое приложение написано в AndEngine, поэтому метод CreateScene() вызывается из SceneManager, который я уверен, работает отлично.

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

Пожалуйста, покажите короткую, но полную программу, демонстрирующую проблему. Я уверен, что проблема заключается в коде, который вы не указали, например, если ваша инициализация случайно имеет локальную переменную в конструкторе, оставив переменную * instance * uninitialized. –

+1

После редактирования я вижу массив 'врагов', но где он инициализирован? Убедитесь, что вы инициализировали массив. –

+0

Ищите «врагов = нуль» в вашем коде. –

ответ

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++, где Bm() вместо Xm() будет вызываться из конструктора базового класса ,

Конструктор В() вызывается автоматически перед выполнением какого-либо кода из конструктора Х(), и поэтому метод Xm() вызывается до любого кода в пределах конструктора Х() получает контроль.

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 закончена.

Кроме того, вы пишете: I (попытка) динамически назначать членов этого массива объектов врага, когда экран коснулся, но я вижу, что код запускается на тайм-аут:

at com.example.menutest.SceneManager$1.onTimePassed(SceneManager.java:118) 
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 

дает ли это вам никакой полезной информации?

+0

Да, это говорит, что «враги имеют нулевое значение». Является ли моя инициализация неправильной? – lkjhgfdsa

+0

Возможно ... :(Я немного соблазнился спросить вас, почему вы хотите использовать собственный массив, а не использовать класс Array. – Bex

+0

если я попытался сделать 'враги = новый враг [100];' внутри spawnEnemy() метод непосредственно перед NPE, заменит ли он существующих членов? – lkjhgfdsa

Смежные вопросы