web-dev-qa-db-ja.com

nullポインタ例外、「nullオブジェクト参照のフィールドから読み取ろうとしました」

ユーザーがタスクのリストを入力し、そのリストが配列に保存されるアプリを作成しています。配列内の各タスクは、Assignmentクラスのインスタンスです。しかし、Javaでは、配列の作成後に要素を配列に追加することは不可能であることを認識しました。そこで、私はtasksという配列を作成しましたこれは多くのnull値で構成されています:Assignment[]tasks = {null, null, null, null, null, null, null, null, null, null, null, null};。タスクを配列に追加する場合は、次のnull値をオブジェクトで置き換えるだけです。ただし、タスクのみの配列も必要です。 null値がないため、nullでないすべての要素に対してfull_tasksという配列を作成しました。

for (Assignment task: tasks) {
    if (task != null) {
        realLength += 1;
    }
}

Assignment[] full_tasks = new Assignment[realLength];

for (int i=0; i <= full_tasks.length - 1; i++) {
        full_tasks[i] = new Assignment(tasks[i].name, tasks[i].days_due, tasks[i].time);
}

したがって、full_tasks配列はすべてのタスクの配列である必要がありますが、どれもnullではありませんよね?ただし、アプリを実行すると、アクティビティを起動できません。エラーメッセージは、nullポインター例外が原因で発生します。

 Caused by: Java.lang.NullPointerException: Attempt to read from field 'Java.lang.String com.example.lb.homeworkappv11.Assignment.name' on a null object reference
        at com.example.lb.homeworkappv11.Schedule.sortTasks(Schedule.Java:64)

エラーが指す行は次のとおりです。

full_tasks[i] = new Assignment(tasks[i].name, tasks[i].days_due, tasks[i].time);

Nullオブジェクト参照が何であるかはまだ完全にはわかりませんが、full_tasks配列の要素の1つがnullであることを意味します。それは正しいでしょうか?そうであれば、full_tasks配列がonlytasks配列のnull以外の要素であることを確認するにはどうすればよいですか?

どうもありがとうございます!

編集:割り当てクラスのコンストラクター関数は次のとおりです。

public Assignment(String name, int days, int time) {
    this.name = name;
    this.days_due = days;
    this.time = time;
    this.toSortBy = "nothing";
}
6
Lucas B

null参照は、まさにnullです。あなたのコードではそれはtasks[i].nameであり、ここでtasks[i]nameを呼び出そうとすると、tasks[i]nullになります。

あなたのコードが間違いなくNullPointerExceptionをスローする、私が考えることができる1つのシナリオがあります。したがって、タスク配列は次のようになると想定します。

tasks = [task0, null, task2, task3, null, task5]

次に、full_tasksのサイズは4になりますが

for (int i=0; i <= full_tasks.length - 1; i++) {
        full_tasks[i] = new Assignment(tasks[i].name, tasks[i].days_due, tasks[i].time);
}

i == 1nullであるため、tasks[1]になるとすぐに[〜#〜] npe [〜#〜]がスローされます。

したがって、full_tasksにnull以外のタスクのみを入力する場合は、tasksの正しいインデックスを取得していることを確認してください。

2
Sascha Kolberg

これが私の考えです

nullではない数値要素を見つけているだけです。配列のどこにnullが存在するかはわかりません。

最初の要素のみがnullであるとします。したがって、realLengthは7になります。後者のforループは、i=0からi=7まで実行されます。 i=0の場合、tasks[i].nameは最初の要素のnameフィールドにアクセスしようとします。しかし、最初の要素はたまたまnullです。それは物事がうまくいかないところです。

ソリューション:

いくつかの解決策があります。私が考えることができる最も効率的なものはArrayListを使用しています。

配列の使用を回避するには、nullではないすべての要素のインデックスを保存する必要があります。それは一つの方法です。

ここに別のものがあります:

for (Assignment task: tasks) {
  if (task != null) {
    realLength += 1;
  }
}
Assignment[] full_tasks = new Assignment[realLength];
int count = 0;
for (Assignment task: tasks) {
  if (task != null) {
    full_tasks[count] = new Assignment(task.name, tasks.days_due, task.time);
    count++;
  }
}
1
Wololo

tasks配列をfull_tasks配列にコピーして圧縮しようとしているようです(null要素を削除しています)。2番目のループでtasks[i]にnullかどうかをチェックせずにアクセスしているため、これは部分的に正しくありません。 。

の代わりに:

for (int i=0; i <= full_tasks.length - 1; i++) {
    full_tasks[i] = new Assignment(tasks[i].name, tasks[i].days_due, tasks[i].time);
}

あなたはこのようなものを書くことができます:

for (int i = 0, f = 0; i < tasks.length; i++) {
    if (tasks[i] != null) {
        full_tasks[f] = new Assignment(tasks[i].name, tasks[i].days_due, tasks[i].time);
        f++;
    }
}

しかし、元の問題を解決するために、配列に要素を追加できないという事実に関して、単純な配列の代わりに ArrayList を使用することをお勧めします。これにより、ArrayList.add(assignment)を使用して項目を追加し、ArrayList.remove(index)を使用してそれらを再度削除することができます。

0
Floern

「タスク」リストが空のようです。値が入力されていることを確認するか、次のようにnullチェックを配置します。

if(tasks[i] !=null) {

full_tasks[i] = new Assignment(tasks[i].name, tasks[i].days_due,  tasks[i].time);

 }
0
Rehman

Nullは存在しないものと考えることができます。たとえば、task.nameを取得しようとすると、タスクはnullとなり、エラーが発生します。さえ存在しません。

実際、コードが現在実行しているのは、元の配列内のnull以外の項目の数を確認し、配列の最初のn項目を余分に抽出して新しい配列に変換することです。

つまり、リストが{null, null, non-null, non-null}の場合、2つのnull以外のアイテムがありますが、コードは{null, null}である最初の2つのアイテムのリストを誤って抽出します

編集、実際にやりたいことを行うには:

ArrayList<Assignment> fullTaskList = new ArrayList<Assignment>();
for (Assignment task: tasks) {
    if (task != null) {
        fullTaskList.add(task);
    }
}
//optional
Assignment[] fullTasks = fullTaskList.toArray(new Assignment[fullTaskList.size()]);
0
Derek Fung

あなたのコードの問題はここにあります:

_(tasks[i].name, tasks[i].days_due, tasks[i].time).
_

実際のサイズを数えていますが、その間にいくつかのnull値が含まれている可能性があり、そのため、リストtasks [i]からnullオブジェクトが取得されます。


これを解決するには、配列の代わりにリストを使用することをお勧めします。リストは必要に応じて増減できます。オブジェクトタイプのアイテムを追加または削除するだけです。例えば:

_List<Assignment> list = new ArrayList<>();
Assignment assignment1 = new Assignment(etc.);
list.add(assignment1);
list.get(0) //-> returns the Assignment object that you added.
_

次に、list.size()を使用してサイズを取得し、そこにあるアイテムの数を確認したり、最後のアイテムを削除したりできます。リストに新しいアイテムを追加しても問題はありません。

0
George