【问题标题】:Why do I get NullPointerException?为什么我会得到 NullPointerException?
【发布时间】:2012-09-25 22:08:02
【问题描述】:

我正在制作的程序出现问题,我无法弄清楚问题出在哪里。我做了几个较小的测试类来尝试找出问题所在,但我不明白。我确信这是关于数组如何工作的一些基本知识,但我似乎不记得是什么。所以我在这里发布课程,希望你们知道什么是错的。谢谢!

public class Main {

    public static void main(String[] args) {
        TestArray t = new TestArray(8);
        t.set(1, 15);
        t.print();
    }

}


public class TestArray {
    private Word[] a;

    public TestArray(int i){
        a = new Word[i];
    }

    public void set(int pos, long value){
        a[pos].set(value);
    }

    public void print(){
        for(Word w : a){
            System.out.println(w);
        }
    }
}



public class Word {
    private long value;

    public Word(long value){
        this.value = value;
    }

    public void set(long value){
        this.value = value;
    }

    public String toString(){
        return String.valueOf(value);
    }
}

当我尝试执行 t.set(1,15) 时,错误发生并且 Eclipse 说该行有问题:a[pos].set(value);

【问题讨论】:

  • 发布堆栈跟踪。你在哪条线上?

标签: java arrays nullpointerexception


【解决方案1】:

您没有初始化Word[] a 变量的实际元素。如果它们在您的 TestArray.set 方法中为空,则初始化它们。

if (a[pos] == null)
    a[pos] = new Word(value);
else 
    a[pos].set(value);

Java 中的对象数组的值被初始化为null,这与原始数组的初始化方式相反(全零或等价物)。因此,当您通过new Word[i] 创建数组时,实际上是在创建一个由null 元素组成的数组,您必须相应地设置它们。

在 set 方法中执行此操作可确保您不会创建任何未使用的 Word 对象。这称为lazy initialization。另一种方法是在构造函数中将它们全部初始化为某个默认值:

public TestArray(int i){
    a = new Word[i];
    for (int index = 0; index < i; index++) {
        a[index] = new Word(0); // Or some other default besides 0, like -1
    }
}

根据您的评论:

这似乎是最好的方法,但我实际上尝试这样做:(for-each 代码)。在问这里之前,那是行不通的。为什么?

您的代码:

public TestArray(int i) {
    a = new Word[i];
    for(Word w:a) {
        w = new Word(0);
    }
}

不起作用,因为 w 不是像 a[index] 那样的实际引用。在数组上的 for-each 循环中,您的代码在编译时实际上是这样做的:

for (int $i = 0; $i < a.length; $i++) { 
    Word w = a[$i];
    w = new Word(0);
}

如您所见,您正在为局部变量w 分配一个值,而不是为a 中的实际元素分配一个值,因此不会更改数组。一句话:不要被$ 变量抛弃,因为 1) $ 在 Java 变量名中是合法的(尽管你永远不应该明确地使用它们)和 2) Java 在编译你的代码时会生成这些变量(它可以在适当的调试器中看到)。

【讨论】:

  • 这似乎是最好的方法,但我实际上尝试这样做: public TestArray(int i){ a = new Word[i]; for(Word w:a){ w = new Word(0); } } 在这里问之前,这是行不通的。为什么?
  • 我认为这是因为只有空值而不是单词所以你不能遍历单词。我不知道你实际上创建了一个空值数组。
  • 所以你永远不能在对象数组上使用 for each?
  • 您可以使用它(您的打印方法是完全合法的),但您不能修改来自 for-each 的实际数组的引用。
  • 我想我现在明白了,在 for each 代码中发生的事情是 w 设置为 a[$i] 的内容,然后更改为 new Word(0) 然后丢弃以被删除由垃圾收集器。我说的对吗?
【解决方案2】:

你分配了一个数组,但在访问元素之前你没有在数组元素中放置任何东西。

a[pos].set(value);

尝试访问 a[pos] 中的任何内容,它为 null。

您需要遍历数组,为每个数组元素分配一个新的 TestArray 实例。

【讨论】:

  • Eric 是对的,你需要用 Word 对象初始化每个数组。您可以在设置值之前在 tje 构造函数中执行此操作,或者在 set 方法中更好地执行此操作
  • public TestArray(int i){ a = new Word[i]; for(Word w : a){ w = new Word(0); } } 不起作用。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-11-22
  • 1970-01-01
  • 2013-11-06
  • 2012-12-06
  • 2014-01-29
相关资源
最近更新 更多