Java 什么是NullPointerException,如何修复它?

Java 什么是NullPointerException,如何修复它?,java,nullpointerexception,Java,Nullpointerexception,什么是空指针异常(java.lang.NullPointerException)以及是什么导致了它们 String a = null; System.out.println(a.toString()); // NullPointerException will be thrown 可以使用哪些方法/工具来确定原因,从而阻止异常导致程序过早终止?NullPointerExceptions是当您尝试使用指向内存中无位置(null)的引用时发生的异常,就好像它在引用对象一样。对空引用调用方法或尝试访

什么是空指针异常(
java.lang.NullPointerException
)以及是什么导致了它们

String a = null;
System.out.println(a.toString()); // NullPointerException will be thrown

可以使用哪些方法/工具来确定原因,从而阻止异常导致程序过早终止?

NullPointerExceptions是当您尝试使用指向内存中无位置(null)的引用时发生的异常,就好像它在引用对象一样。对空引用调用方法或尝试访问空引用的字段将触发
NullPointerException
。这些是最常见的,但javadoc页面上列出了其他方法

String a = null;
System.out.println(a.toString()); // NullPointerException will be thrown
可能我能想出的最快的示例代码来说明
NullPointerException

public class Example {

    public static void main(String[] args) {
        Object obj = null;
        obj.hashCode();
    }

}
String a = null;
System.out.println(a.toString()); // NullPointerException will be thrown
main
内的第一行,我将
对象
reference
obj
显式设置为
null
。这意味着我有一个引用,但它没有指向任何对象。之后,我尝试通过调用对象上的方法,将引用视为指向对象。这会导致
NullPointerException
,因为在引用所指向的位置没有要执行的代码

String a = null;
System.out.println(a.toString()); // NullPointerException will be thrown

(这是一个技术问题,但我认为值得一提:指向null的引用与指向无效内存位置的C指针不同。null指针实际上不指向任何地方,这与指向恰好无效的位置略有不同。)

这就像你试图访问一个
为空的对象一样。考虑下面的例子:

TypeA objA;
String a = null;
System.out.println(a.toString()); // NullPointerException will be thrown
此时,您刚刚声明了该对象,但未初始化或实例化该对象。每当您试图访问其中的任何属性或方法时,它都会抛出有意义的
NullPointerException

String a = null;
System.out.println(a.toString()); // NullPointerException will be thrown
请参见下面的示例:

String a = null;
System.out.println(a.toString()); // NullPointerException will be thrown

null
指针不指向任何地方。当您取消引用指针
p
时,您说“将存储在“p”中的位置的数据提供给我”。当
p
null
指针时,存储在
p
中的位置是
无处
,您说的是“将“无处”位置的数据提供给我”“。显然,它不能这样做,因此它会抛出一个
空指针异常

String a = null;
System.out.println(a.toString()); // NullPointerException will be thrown

一般来说,这是因为某些东西没有正确初始化。

当您声明引用变量(即对象)时,实际上是在创建指向对象的指针。考虑下面的代码,其中声明一个原始类型的变量<代码> int <代码>:

String a = null;
System.out.println(a.toString()); // NullPointerException will be thrown
int x;
x = 10;
在本例中,变量
x
是一个
int
,Java将为您将其初始化为
0
。当您在第二行指定
10
的值时,
10
的值将写入
x
引用的内存位置

String a = null;
System.out.println(a.toString()); // NullPointerException will be thrown
但是,当您试图声明引用类型时,会发生一些不同的情况。以下面的代码为例:

String a = null;
System.out.println(a.toString()); // NullPointerException will be thrown
Integer num;
num = new Integer(10);
第一行声明了一个名为
num
的变量,但它实际上还没有包含基元值。相反,它包含一个指针(因为类型是引用类型的
Integer
)。由于您还没有说要指向什么,Java将其设置为
null
,这意味着“我没有指向任何东西”

String a = null;
System.out.println(a.toString()); // NullPointerException will be thrown
在第二行中,使用
new
关键字实例化(或创建)类型为
Integer
的对象,指针变量
num
分配给该
Integer
对象

String a = null;
System.out.println(a.toString()); // NullPointerException will be thrown
当您声明变量但在尝试使用变量内容(称为取消引用)之前未创建对象并将其分配给变量时,会发生
NullPointerException
(NPE)。所以你指的是一些实际上并不存在的东西

String a = null;
System.out.println(a.toString()); // NullPointerException will be thrown
取消引用通常发生在使用
访问方法或字段,或使用
[
索引数组时

String a = null;
System.out.println(a.toString()); // NullPointerException will be thrown
如果在创建对象之前尝试取消对
num
的引用,则会得到
NullPointerException
。在最简单的情况下,编译器会发现问题,并让您知道“
num可能尚未初始化
”,但有时您可能会编写不直接创建对象的代码

String a = null;
System.out.println(a.toString()); // NullPointerException will be thrown
例如,您可能有如下方法:

String a = null;
System.out.println(a.toString()); // NullPointerException will be thrown
public void doSomething(SomeObject obj) {
   // Do something to obj, assumes obj is not null
   obj.myMethod();
}
在这种情况下,您不是在创建对象
obj
,而是假设它是在调用
doSomething()
方法之前创建的。注意,可以这样调用该方法:

String a = null;
System.out.println(a.toString()); // NullPointerException will be thrown
doSomething(null);
private static String[] foo = new String[2];
在这种情况下,
obj
null
,语句
obj.myMethod()
将抛出
NullPointerException

String a = null;
System.out.println(a.toString()); // NullPointerException will be thrown
如果该方法打算像上述方法那样对传入对象执行某些操作,则可以抛出
NullPointerException
,因为这是一个程序员错误,程序员需要该信息进行调试

String a = null;
System.out.println(a.toString()); // NullPointerException will be thrown
除了由于方法的逻辑而引发的
NullPointerException
s之外,您还可以检查
null
值的方法参数,并通过在方法开头附近添加类似以下内容来显式引发NPE:

String a = null;
System.out.println(a.toString()); // NullPointerException will be thrown
// Throws an NPE with a custom error message if obj is null
Objects.requireNonNull(obj, "obj must not be null");
请注意,在错误消息中明确指出哪个对象不能为
null
,这是很有帮助的。验证这一点的好处是:1)您可以返回自己更清晰的错误消息,2)对于方法的其余部分,您知道除非重新分配
obj
,否则它不是null,可以安全地取消引用

String a = null;
System.out.println(a.toString()); // NullPointerException will be thrown
或者,在某些情况下,方法的目的可能不仅仅是对传入的对象进行操作,因此可以接受null参数。在这种情况下,您需要检查null参数
private static String[] foo = new String[2];