空指针异常是什么 (Java.lang.NullPointerException
) 是什么原因导致的?
可以使用哪些方法/工具来确定原因,以便阻止异常导致程序过早终止?
声明引用变量 (即对象) 时,实际上是在创建指向对象的指针。请考虑以下代码,其中声明了原始类型的变量Int
:
Int x;
X = 10;
在这个例子中,变量X
是一个Int
Java 将把它初始化为0
给你的当你分配它的值时10
第二行,你的价值10
写入所引用的内存位置X
.
但是,当您尝试声明引用时类型不同的事情发生了取以下代码:
整数 num;
Num = 新整数 (10);
第一行声明了一个名为Num
,但是它实际上还不包含原始值。相反,它包含一个指针 (因为类型是整数
这是一个引用类型)。因为你还没有说要指向什么,所以 Java 将它设置为Null
意思是"我指的是没什么”。
在第二行,新的
关键字用于实例化 (或创建) 类型的对象整数
和指针变量Num
被分配到那个整数
对象。
的NullPointerException
声明变量但未创建对象时发生。所以你指的是不存在的东西。
如果您试图取消引用Num
在创建对象之前,您会得到NullPointerException
。在最琐碎的情况下,编译器会抓住问题,让你知道可能没有初始化 num
,”但是有时您可能会编写不直接创建对象的代码。
例如,您可能有如下方法:
调用父类做点什么 (SomeObject obj) {
//对 obj 做点什么
}
在这种情况下,您没有创建对象Obj
,而是假设它是在做某事
调用了方法。注意,可以像这样调用方法:
做点什么 (无效);
在这种情况下Obj
是Null
。如果该方法旨在对传入对象执行某些操作,则抛出NullPointerException
因为这是一个程序员错误,程序员需要这些信息来进行调试。
或者,在某些情况下,该方法的目的不仅仅是对传入的对象进行操作,因此可以接受 null 参数。在这种情况下,你需要检查空参数和行为不同。您还应该在文档中解释这一点。例如,做某事
可以写成:
/* *
* @ Param obj 任选富于 ____。在这种情况下,可能为 null
结果将会是…
*/
调用父类做点什么 (SomeObject obj) {
如果 (obj!= null) {
做点什么
} 其他 {
做点别的
}
}
编辑从 @ Perimosh
我想添加一些东西,但是不能评论,所以我在这里添加它。你从来没有抓到过 NullPointerException!这是一个可怕的做法。如果你这样做,这意味着很可能你的代码中有一个错误。
NullPointerException
S 是当您尝试使用指向内存中没有位置 (null) 的引用时出现的异常,就好像它引用了一个对象一样。对空引用调用方法或尝试访问空引用的字段将触发NullPointerException
。这些是最常见的,但是在NullPointerException
Javadoc 页。
可能是我能想出的最快的示例代码来说明NullPointerException
将是:
公共类示例 {
公共静态 void main (字符串 [] args) {
对象 obj = null;
Obj.hashCode ();
}
}
在里面的第一行主要的
,我明确设置了对象
参考Obj
等于Null
。这意味着我有一个引用,但是它没有指向任何对象。之后,我试图通过调用对象上的方法来将引用视为指向对象。这导致了NullPointerException
因为在引用指向的位置没有要执行的代码。
(这是一个技术问题,但我认为值得一提的是: 指向 null 的引用与指向无效内存位置的 C 指针不同。空指针实际上没有指向任何地方,这与指向碰巧无效的位置有微妙的不同。))
一个好的开始是JavaDocs。他们涵盖了这一点:
当应用程序试图在以下情况下使用 null 时引发 对象是必需的。这些包括:
- 调用 null 对象的实例方法。
- 访问或修改空对象的字段。
- 将 null 的长度视为数组。
- 像数组一样访问或修改 null 的插槽。
- 抛出 null,就好像它是一个可抛出的值一样。
应用程序应该抛出这个类的实例来指示其他 Null 对象的非法使用。
如果您尝试使用空引用,也会出现这种情况同步
也会抛出这个异常根据 JLS:
同步声明: 同步 (表达式) 块
- 否则,如果表达式的值为 null,则
NullPointerException
被扔了
所以你有一个NullPointerException
。你怎么修的?让我们举一个简单的例子NullPointerException
:
公共类打印机 {
私有字符串名称;
公共 void setName (字符串名称) {
名称 = 名称;
}
公共空白打印 () {
打印字符串 (名称);
}
私有 printprint String (字符串 s) {
系统。输出。 println (“s.长度 ()”);
}
公共静态 void main (字符串 [] args) {
打印机打印机 = 新打印机 ();
打印机.print ();
}
}
标识 null 值
第一步是准确识别导致异常的值有哪些。为此,我们需要做一些调试。学习阅读 a 是很重要的Stacktrace。这将向您显示引发异常的位置:
线程 “main” java.lang.NullPointerException 中的异常
在打印机。打印字符串 (打印机 java
在打印机。打印 (打印机。 java: 9)
在打印机。主 (打印机。 java: 19)
在这里,我们看到在 13 号线 (在打印字符串
方法)。查看行并检查哪些值是空的 添加日志记录语句或使用调试器。我们发现S
为 null,并调用长度
方法引发异常。我们可以看到,当程序停止抛出异常时,美国长度 ()
从方法中删除。
跟踪这些值来自哪里
接下来检查这个值来自哪里。通过跟踪方法的调用方,我们可以看到S
是通过与打印字符串 (名称)
在打印 ()
方法,和这个名字
为 null。
应该设置这些值的跟踪
在哪里这个名字
定了?在SetName (字符串)
方法。有了更多的调试,我们可以看到这个方法根本没有被调用。如果调用了该方法,请确保检查订单调用这些方法,而不调用 set 方法之后打印方法。
这足以给我们一个解决方案:打印机.setName ()
在打电话之前打印机.print ()
.
变量可以有一个默认值(和SetName
可以防止它被设置为 null):
私有字符串名称 = "";
要么是打印
或者打印字符串
方法可以检查 null,例如:
打印字符串 (
NullPointerException
(NPE)?正如你应该知道的,Java 类型分为原始类型 (布尔
, Int
等) 和引用类型。Java 中的引用类型允许您使用特殊值Null
这是说 “没有对象” 的 Java 方式。
ANullPointerException
每当您的程序尝试使用Null
好像是真正的参考。例如,如果你这样写:
公共类测试 {
公共静态 void main (字符串 [] args) {
字符串 foo = null;
长度 ();/这里
}
}
标有 “这里” 的语句将尝试运行长度 ()
A 上的方法Null
参考,这将抛出一个NullPointerException
.
你可以使用多种方式Null
将导致 a 的值NullPointerException
。事实上,你唯一的东西可以用 a 做Null
在不引起 NPE 的情况下:
= =
或者!=
运营商,或者替代 instanceof
.假设我编译并运行上面的程序:
$ Java c 测试.java
Java 测试
线程 “main” java.lang.NullPointerException 中的异常
在 Test.main (测试.java: 4)
$
第一次观察: 编译成功!程序中的问题不是编译错误。这是一个运行时错误。(一些 ide 可能会警告你的程序总是会抛出异常.但是标准Javac
编译器没有。)
第二个观察: 当我运行程序时,它会输出两行 “gobbledy-gook”。错了!!这不是废话。这是一个 stacktrace.它提供了重要信息如果你花时间仔细阅读,这将有助于你追踪代码中的错误。
所以让我们看看它是怎么说的:
线程 “main” java.lang.NullPointerException 中的异常
堆栈跟踪的第一行告诉你一些事情:
Java.lang.NullPointerException
.NullPointerException
在这方面是不寻常的,因为它很少有错误信息。第二行是诊断 NPE 最重要的一行。
在 Test.main (测试.java: 4)
这告诉我们很多事情:
主要的
的方法测试
上课。如果你计算上面文件中的行,第四行是我用 “这里” 注释标记的行。
请注意,在一个更复杂的例子中,NPE 堆栈跟踪中会有很多行。但是你可以确定第二行 (第一个 “at” 行) 会告诉你 NPE 被扔在哪里 1.
简而言之,堆栈跟踪将明确地告诉我们程序的哪个语句抛出了 NPE。
1-不太对。有些东西叫做嵌套异常.
就像你试图访问一个对象Null
。考虑下面的例子:
ObjA 型;
在这个时候,你刚刚宣布这个对象初始化或实例化。当你试图访问其中的任何属性或方法时,它会抛出NullPointerException
这是有道理的。
请参见下面的示例:
字符串 a = null;
将抛出 System.out.println (a.toString ());//NullPointerException
当应用程序试图在需要对象的情况下使用 null 时,会引发 null 指针异常。这些包括:
Null
对象。Null
对象。Null
好像是一个数组。Null
好像是一个数组。Null
就好像它是一个可投掷的值。应用程序应该抛出该类的实例来指示Null
对象。
参考:Http://docs.oracle.com/javase/8/docs/api/java/lang/NullPointerException.html
ANull
Pointer 是一个指向任何地方的指针。解引用指针时P
,你说 “把存储在“ p ”中的位置的数据给我。当P
是一个Null
指针,存储在P
是无处可去
,你是说 “现在把位置的数据给我”。显然,它不能这样做,所以它会抛出一个空指针异常
.
一般来说,这是因为一些东西没有被正确初始化。
已经有很多解释来解释它是如何发生的以及如何修复它,但是你也应该遵循最佳实践要避免NullPointerException
一点都没有
另见: 最佳实践的好列表
我想补充一点,非常重要的是,充分利用决赛
修饰语。 在 Java 中使用 “最终” 修饰符
总结:
决赛
实现良好初始化的修饰符。@ NotNull
和@ 可空
如果 (“知道对象”。等于 (不知道对象)
价值 ()
通过 toString ()。StringUtils
方法StringUtils。isEmpty (空)
.空指针异常是指在不初始化对象的情况下使用对象的指示器。
例如,下面是一个学生班,它将在我们的代码中使用它。
公开课学生 {
私有 int id;
公共 int getId () {
返回这个 id;
}
公共 setId (int newId) {
这个 id = newId;
}
}
下面的代码给你一个空指针异常。
公立学校
学生学生;
公立学校 () {
试试 {
学生.getId ();
}
捕获 (异常 e) {
System.out.println (“空指针异常”);
}
}
}
因为你用的是学生
,但是你忘了像 如下所示的正确代码:
公立学校
学生学生;
公立学校 () {
试试 {
学生 = 新学生 ();
学生.setId (12);
学生.getId ();
}
捕获 (异常 e) {
System.out.println (“空指针异常”);
}
}
}
在 Java 中,所有东西 (不包括基本类型) 都是以类的形式存在的。
如果你想使用任何对象,那么你有两个阶段:
示例:
对象对象;
对象 = 新对象 ();
数组概念也一样:
项目 [] = 新项目 [5];
项目 [0] = 新项目 ();
如果没有给出初始化部分,则NullPointerException
出现。
在Java您声明的所有变量实际上都是对对象 (或基本体) 的 “引用”,而不是对象本身。
当您尝试执行一个对象方法时,引用会要求活对象执行该方法。但是,如果引用引用 NULL (无、零、无效、 nada),则该方法无法执行。然后运行时通过抛出一个 NullPointerException 来让你知道这一点。
你的引用是 “指向” null,因此是 “Null-> Pointer”。
对象存在于虚拟机内存空间中,访问它的唯一方法是使用这个
参考资料。举这个例子:
公共类一些 {
私有 int id;
公共 int getId () {
返回这个 id;
}
公共 setId (int newId) {
这个 id = newId;
}
}
在代码的另一个地方:
指向类型为 Some () 的新对象;//
一些其他的引用 = null;/
//执行 setId 方法,现在私有 var id 为 1
System.out.println (参考.getId ());//将 1 打印到控制台
现在它们都指向了唯一的对象。
引用 = null;//“引用” 现在指向 null。
但是 “其他引用” 仍然指向 “真实” 对象,所以这个 print 1 也是.
系统输出打印输出 (其他参考 getId ());
猜会发生什么
System.out.println (引用.getId ());//: 因为 “引用” 指向 NULL remember,所以 S 抛出 NullPointerException.
这是一件重要的事情 -- 当没有更多的对象引用时 (在上面的例子中,当参考
和其他参考
两者都指向 null),则对象是 “不可访问的”。我们无法使用它,所以这个对象已经准备好被垃圾收集,在某个时候,虚拟机将释放这个对象使用的内存,并分配另一个内存。
A 的另一次出现NullPointerException
当声明对象数组时发生,然后立即尝试取消引用其中的元素。
【】短语 = 【 10 】新串;
串关键词 = "鸟";
用于 (字符串短语: 短语) {
系统。输出。 println (短语。等于 (关键短语));
}
如果比较顺序相反,可以避免这种特殊的 NPE; 即使用。平等
在保证的非空对象上。
数组内部的所有元素初始化为它们的公共初始值; 对于任何类型的对象数组,这意味着所有元素都是Null
.
你必须初始化数组中的元素之前访问或取消引用它们。
字符串 [] 短语 = 新字符串 [] {“鸟” 、 “我的鸟” 、 “鸟”};
串关键词 = "鸟";
用于 (字符串短语: 短语) {
系统。输出。 println (短语。等于 (关键短语));
}