Исключение нулевого указателя для массивов

1

Я получаю исключение NullPointerException, кажется, что программа не может найти nums (массив)

Класс:

/**
 *Author: Chris Cherian
 *Date: 4/30/14
 *Desc: This program organizes numbers into 3 arrays - Even, Odd, and Negative.
 */
public class IntegerArray
{
    /**
     *The array that holds all the numbers.    
     */
    int nums [];

    /**
     *Holds count of the odds.
     */
    private int oddCount = 0;

    /**
     *The numbers in the array.
     */
    private int length;

    /**
     *Holds count of the positives.
     */
    private int posCount;


    public IntegerArray(int[] array)
    {
        nums = array;
    }

    /**
     *The nuber of elements in the array.
     */
    private final int TOTALNUMS = nums.length;

    /**
     *The array that holds all the even numbers.    
     */
    private int[] evens = new int[TOTALNUMS - this.getOddCount()];

    /**
     *The array that holds all the odd numbers.
     */
    private int[] odds = new int[this.getOddCount()];

    /**
     *The array that holds all the negative numbers.
     */
    private int[] negs = new int[TOTALNUMS - this.getPosCount()];

    int evenCounter = 0;

    /**
     *Gathers the total number of odds
     *@return The number of odd numbers
     */
    public int getOddCount()
    {
        for(int i = 0; i <= TOTALNUMS; i++)
        {
            if(nums[i]%2 != 0)
            {
                oddCount++;
            }
        }
        return oddCount;
    }

    /**
     *Gathers number of positives
     *@return posCount The number of positive numbers
     */
    public int getPosCount()
    {
        for(int i = 0; i <= TOTALNUMS; i++)
        {
            if(nums[i] > 0)
            {
                posCount++;
            }
        }

        return posCount;
    }
    public int[] organizeEvens()
    {
        for(int i = 0; i < nums.length; i++)
        {
            if(nums[i]%2 == 0)
            {
                evens[evenCounter] = nums[i];
                evenCounter++;
            }
        }
        return evens;
    }

    int oddCounter = 0;
    public int[] organizeOdds()
    {
        for(int i = 0; i < nums.length; i++)
        {
            if(nums[i]%2 != 0)
            {
                odds[evenCounter] = nums[i];
                oddCounter++;
            }
        }
        return odds;
    }

    int negCounter = 0;

    public int[] organizeNegs()
    {
        for(int i = 0; i < nums.length; i++)
        {
            if(nums[i]%2 == 0)
            {
                negs[negCounter] = nums[i];
                negCounter++;
            }
        }
        return negs;
    }
}

Клиент:

import java.util.Scanner;

public class IntegerArrayClient
{
    public static void main(String[] jackofspades)
    {
        Die die1 = new Die(200);
        Scanner keyboard = new Scanner(System.in);

        System.out.println("How many numbers would you like to organize?");
        int numbers = keyboard.nextInt();

        int[] numbersarray = new int[numbers];

        for(int i = 0; i < numbers; i++)
        {
            numbersarray[i] = (die1.Roll() - 200);
        }

        IntegerArray numholder = new IntegerArray(numbersarray);

        int evenCount = (numbersarray.length - numholder.getOddCount());

        for(int i = 0; i < evenCount; i++)
        {
            System.out.println(numholder.organizeEvens() + "\t");
        }

    }
}

Сообщение об ошибке, которое я получаю:

Exception in thread "main" java.lang.NullPointerException
    at IntegerArray.<init>(IntegerArray.java:37)
    at IntegerArrayClient.main(IntegerArrayClient.java:20)
  • 0
    И где вы думаете , инициализировать nums ?
  • 0
    Но числа должны быть отформатированы в массив от клиента, который может иметь множество элементов
Показать ещё 6 комментариев
Теги:
arrays
nullpointerexception

4 ответа

1
Лучший ответ

Проблема в том, что в вашем коде есть предположение, что

private final int TOTALNUMS = nums.length;    

будет выполняться после конструктора, поскольку по тексту он следует за ним. Это неверное предположение - эта строка выполняется перед конструктором, когда число nums все равно null. Это и вызывает исключение.

Чтобы устранить эту проблему, переместите инициализацию TOTALNUMS в конструктор:

private final int TOTALNUMS; // It OK to leave it final - you are allowed to set it in the constructor
...
public IntegerArray(int[] array) {
    nums = array;
    TOTALNUMS = nums.length; // If nums is set to a non-null array, this would not cause an exception
}

Наконец, обратите внимание, что нет смысла указывать отдельную final переменную для длины nums, поскольку ее длина всегда доступна вам, и вам не нужно "синхронизировать" эти два, если вы решите установить nums на другой массив позже.

  • 0
    Куда мне его переместить?
1

Я предполагаю, что строка 37 является следующей:

   private final int TOTALNUMS = nums.length;

Проблема в том, что nums не была инициализирована в этой точке, и поэтому она по-прежнему имеет начальное значение по умолчанию. Поэтому выполнение num.length вызывает NPE.

Как так?

Ну, вы инициализируете nums в конструкторе. Bur код в теле конструктора выполняется только после того, как инициализаторы для переменных экземпляра все были выполнены.

Вам нужно инициализировать TOTALNUMS, evens, odds и т.д. В конструкторе, поскольку все они зависят от значения, переданного в параметре array конструктора.

1

Этот фрагмент кода

private final int TOTALNUMS = nums.length; 

происходит до того, как nums был инициализирован, он все еще int nums []; - у него нет размеров.

0

Вам нужно искать инициализаторы элементов и когда они выполняются по отношению к конструктору. Они запускаются перед конструктором. Только после этого (во время конструктора) вы инициализируете num, и это после того, как вы попытались использовать num.Length.

Переместите код, который зависит от nums.length, к конструктору, после того, как вы назначили nums, или в методе, который вызывается после того, как объект полностью создан (т.е. Не относится к нему в конструкторе вообще), добавьте другой метод на классе, который возвращает длину).

Попытка сделать слишком много в инициализаторах вызывает проблемы.

См. Первый ответ в этом вопросе:

Стационарный порядок инициализации Java

Или правила Java по порядку инициализации:

http://docs.oracle.com/javase/specs/jls/se7/html/jls-12.html#jls-12.4.2

Все эти строки кода неправильны, поскольку эти строки выполняются по мере создания объекта до конструктора, который инициализирует nums.

  private final int TOTALNUMS = nums.length;    
  private int[] evens = new int[TOTALNUMS - this.getOddCount()];
  private int[] odds = new int[this.getOddCount()];
  private int[] negs = new int[TOTALNUMS - this.getPosCount()];

Я предлагаю преобразовать "evens" в "getEvens()" и вызывать getEvens() из основного, а не из инициализатора. То же самое для каждого из других полей, конвертировать в методы, которые вызываются позже.

  • 0
    Если вы посмотрите, хотя большая часть кода зависит от nums.length. Это можно обойти?
  • 0
    Да, убедитесь, что любой код, который зависит от nums.length, вызывается после того, как объект полностью построен, или, как минимум, после строки в конструкторе, где вы назначаете «nums = array».
Показать ещё 1 комментарий

Ещё вопросы

Сообщество Overcoder
Наверх
Меню