声明引用变量(即对象)时,实际上是在创建指向对象的指针。考虑以下代码,在其中声明原始类型int
的变量:
int x;
x = 10;
在此示例中,变量
x
是
int
,Java会为您将其初始化为
0
。当您在第二行为其分配
10
的值时,您的
10
的值将被写入
x
所引用的存储位置。
但是,当您尝试声明引用类型时,会发生一些不同的事情。采取以下代码:
Integer num;
num = new Integer(10);
第一行声明了一个名为
num
的变量,但实际上它尚未包含原始值。相反,它包含一个指针(因为类型是
Integer
,它是引用类型)。由于您尚未说出要指向的内容,因此Java将其设置为
null
,这意味着“
我没有指向”。
在第二行中,使用
new
关键字实例化(或创建)
Integer
类型的对象,并将指针变量
num
分配给该
Integer
对象。
当您声明变量但未创建对象并将其分配给该变量,然后再尝试使用该变量的内容(称为取消引用)时,就会发生
NullPointerException
。因此,您指向的是实际上不存在的东西。
当使用
.
访问方法或字段或使用
[
索引数组时,通常会发生解除引用。
如果在创建对象之前尝试取消对
num
的引用,则会得到
NullPointerException
。在大多数情况下,编译器会发现问题,并让您知道“
num may not have been initialized
”,但有时您可能会编写不直接创建对象的代码。
例如,您可能具有如下方法:
public void doSomething(SomeObject obj) {
//do something to obj
}
在这种情况下,您不是在创建对象
obj
,而是假设它是在调用
doSomething()
方法之前创建的。注意,可以这样调用方法:
doSomething(null);
在这种情况下,
obj
是
null
。如果该方法旨在对传入的对象做某事,则应该抛出
NullPointerException
,因为这是程序员错误,并且程序员将需要该信息来进行调试。请在异常消息中包括对象变量的名称,例如
Objects.requireNonNull(a, "a");
替代地,在某些情况下,该方法的目的不仅是对传入的对象进行操作,因此null参数是可以接受的。在这种情况下,您将需要检查
空参数并改变行为。您还应该在文档中对此进行解释。例如,
doSomething()
可以写为:
/**
* @param obj An optional foo for ____. May be null, in which case
* the result will be ____.
*/
public void doSomething(SomeObject obj) {
if(obj == null) {
//do something
} else {
//do something else
}
}
最后,
How to pinpoint the exception & cause using Stack Trace
What methods/tools can be used to determine the cause so that you stop
the exception from causing the program to terminate prematurely?
具有发现错误的声纳可以检测NPE。
Can sonar catch null pointer exceptions caused by JVM Dynamically现在,Java 14已添加了新的语言功能,以显示NullPointerException的根本原因。自2006年以来,该语言功能已成为SAP商业JVM的一部分。下面的内容需要2分钟的阅读时间,以了解该惊人的语言功能。
https://jfeatures.com/blog/NullPointerException在Java 14中,以下是示例NullPointerException异常消息:
in thread "main" java.lang.NullPointerException: Cannot invoke "java.util.List.size()" because "list" is null