【问题标题】:What is a NullPointerException, and how do I fix it?什么是 NullPointerException,我该如何解决?
【发布时间】:2025-12-03 15:40:01
【问题描述】:

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

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

【问题讨论】:

    标签: java nullpointerexception


    【解决方案1】:

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

    int x;
    x = 10;
    

    在本例中,变量xint,Java 将为您将其初始化为0。当您在第二行分配10 的值时,您的10 值将写入x 引用的内存位置。

    但是,当您尝试声明引用type 时,会发生不同的情况。取以下代码:

    Integer num;
    num = new Integer(10);
    

    第一行声明了一个名为num 的变量,但它实际上还没有包含原始值。相反,它包含一个指针(因为类型是Integer,它是一个引用类型)。由于您还没有说要指向什么,Java 将其设置为 null,这意味着“我正在指向 nothing”。

    在第二行中,new 关键字用于实例化(或创建)Integer 类型的对象,并将指针变量num 分配给该Integer 对象。

    NullPointerException (NPE) 发生在您声明一个变量但未创建对象并将其分配给该变量之前尝试使用该变量的内容(称为取消引用)。所以你指向的东西实际上并不存在。

    取消引用通常发生在使用. 访问方法或字段,或使用[ 索引数组时。

    如果您尝试在创建对象之前取消引用num,您将获得NullPointerException。在最琐碎的情况下,编译器会发现问题并让您知道“num may not have been initialized”,但有时您可能会编写不直接创建对象的代码。

    例如,你可能有一个方法如下:

    public void doSomething(SomeObject obj) {
       // Do something to obj, assumes obj is not null
       obj.myMethod();
    }
    

    在这种情况下,您不是在创建对象obj,而是假设它是在调用doSomething() 方法之前创建的。注意,可以这样调用方法:

    doSomething(null);
    

    在这种情况下,objnull,而语句 obj.myMethod() 将抛出 NullPointerException

    如果该方法打算像上述方法那样对传入的对象执行某些操作,则抛出 NullPointerException 是合适的,因为这是程序员错误,程序员将需要该信息进行调试。

    除了作为方法逻辑的结果抛出NullPointerExceptions 之外,您还可以检查null 值的方法参数并通过在方法开头附近添加类似以下内容来显式抛出NPE:

    // 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 参数。在这种情况下,您需要检查 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

    可以使用哪些方法/工具来确定原因,以便您停止 导致程序提前终止的异常?

    带有查找错误的声纳可以检测 NPE。 Can sonar catch null pointer exceptions caused by JVM Dynamically

    现在 Java 14 添加了一个新的语言特性来显示 NullPointerException 的根本原因。自 2006 年以来,此语言功能已成为 SAP 商业 JVM 的一部分。

    在 Java 14 中,以下是 NullPointerException 异常消息示例:

    在线程“main”中 java.lang.NullPointerException:无法调用“java.util.List.size()”,因为“list”为空

    【讨论】:

    • "避免此类异常的最佳方法是在您没有自己创建对象时始终检查 null。"如果调用者传递了 null,但 null 不是该方法的有效参数,那么将异常扔回调用者是正确的,因为这是调用者的错。 默默地忽略无效的输入并且在方法中什么都不做是非常糟糕的建议,因为它隐藏了问题。
    • 我会在这篇文章中添加一个注释,解释即使是对原语的赋值也会在使用自动装箱时导致 NPE:如果 b 是 Integerint a=b 可以抛出 NPE。在某些情况下,这会使调试感到困惑。
    • 是否可以从 Web 浏览器捕获 Web 应用程序抛出的 NPE?就像它会显示在 Web 浏览器的视图页面源中一样......
    • 是的,在调用对象上的方法或尝试访问它可能具有的变量之前检查对象是否等于 null。有时结构化代码可以帮助避免空指针异常。例如,当检查带有常量字符串的输入字符串时,您应该从此处的常量字符串开始: if ("SomeString".equals(inputString)) {} //即使 inputString 为 null 也不会引发异常。因此,您可以做很多事情来确保安全。
    • 另一种避免代码中出现NullPointerException 问题的方法是使用@Nullable@NotNull 注释。以下answer 对此有更多信息。尽管此答案专门针对 IntelliJ IDE,但它也适用于其他工具,例如来自 teh cmets 的 apparanet。 (顺便说一句,我不允许直接编辑这个答案,也许作者可以添加它?)
    【解决方案2】:

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

    我能想到的用于说明NullPointerException 的最快示例代码可能是:

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

    main 内的第一行,我明确设置Object 引用obj 等于null。这意味着我有一个引用,但它没有指向任何对象。之后,我尝试通过调用一个方法来将引用视为指向一个对象。这会导致NullPointerException,因为在引用指向的位置没有要执行的代码。

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

    【讨论】:

    • 我理解你在那里写的一切,但这只是因为我已经编码了一段时间并且知道什么是“指针”和“引用”(以及什么是 null,就此而言)。当我试图深入研究这样的解释时,我的学生们用斗鸡眼看着我,因为没有足够的背景。
    • 在实践中获取 NullPointerException 的更常见方法是忘记在使用 like this 之前将成员变量显式初始化为 null 以外的其他值。使用局部变量,编译器会捕捉到这个错误,但在这种情况下它不会。也许这会对您的答案有所帮助?
    • @EJP 我认为你的观点是有效的,所以我更新了答案,使其更清晰,并避免在原来的地方说“指向 null”。
    • @StevePowell 我很久以前就表示我不想改变我的答案。请尊重原作者的意图。
    • 对不起,我是按照这个 * 项目顶部的要求“改进答案”(这个问题的答案是一个协作的努力:如果你看到可以改进的地方,只需编辑回答以改进它!)我不同意你的版本更好,IMO @EJB 有有效点;但是非常欢迎您保持您的答案完整,尽管它令人困惑。
    【解决方案3】:

    什么是 NullPointerException?

    JavaDocs 是一个很好的起点。他们涵盖了这一点:

    在应用程序尝试使用 null 的情况下抛出 对象是必需的。其中包括:

    • 调用空对象的实例方法。
    • 访问或修改空对象的字段。
    • 将 null 的长度视为数组。
    • 访问或修改 null 的槽,就像它是一个数组一样。
    • 将 null 视为 Throwable 值。

    应用程序应抛出此类的实例以指示其他 非法使用空对象。

    同样的情况是,如果您尝试对synchronized 使用空引用,也会抛出此异常per the JLS

    SynchronizedStatement:
        synchronized ( Expression ) Block
    
    • 否则,如果 Expression 的值为 null,则抛出 NullPointerException

    我该如何解决?

    所以你有一个NullPointerException。你如何解决它?让我们举一个简单的例子,它抛出一个NullPointerException

    public class Printer {
        private String name;
    
        public void setName(String name) {
            this.name = name;
        }
    
        public void print() {
            printString(name);
        }
    
        private void printString(String s) {
            System.out.println(s + " (" + s.length() + ")");
        }
    
        public static void main(String[] args) {
            Printer printer = new Printer();
            printer.print();
        }
    }
    

    识别空值

    第一步是准确识别导致异常的值。为此,我们需要进行一些调试。学习阅读 stacktrace 很重要。这将向您显示引发异常的位置:

    Exception in thread "main" java.lang.NullPointerException
        at Printer.printString(Printer.java:13)
        at Printer.print(Printer.java:9)
        at Printer.main(Printer.java:19)
    

    在这里,我们看到在第 13 行抛出了异常(在 printString 方法中)。查看该行并通过以下方式检查哪些值为空 添加日志语句或使用调试器。我们发现s 为null,在其上调用length 方法会抛出异常。我们可以看到,当从方法中删除s.length() 时,程序停止抛出异常。

    追踪这些值的来源

    接下来检查这个值的来源。通过跟踪方法的调用者,我们看到sprint()方法中是用printString(name)传入的,this.name为null。

    跟踪这些值的设置位置

    this.name 设置在哪里?在setName(String) 方法中。通过更多的调试,我们可以看到这个方法根本没有被调用。如果调用了该方法,请务必检查调用这些方法的顺序,并且 set 方法没有在 print 方法之后调用。

    这足以给我们一个解决方案:在调用 printer.print() 之前添加对 printer.setName() 的调用。

    其他修复

    变量可以有一个默认值(并且setName可以防止它被设置为null):

    private String name = "";
    

    printprintString 方法都可以检查是否为空,例如:

    printString((name == null) ? "" : name);
    

    或者你可以设计类,使name总是有一个非空值

    public class Printer {
        private final String name;
    
        public Printer(String name) {
            this.name = Objects.requireNonNull(name);
        }
    
        public void print() {
            printString(name);
        }
    
        private void printString(String s) {
            System.out.println(s + " (" + s.length() + ")");
        }
    
        public static void main(String[] args) {
            Printer printer = new Printer("123");
            printer.print();
        }
    }
    

    另请参阅:

    还是找不到问题

    如果您尝试调试问题但仍然没有解决方案,您可以发布问题以获得更多帮助,但请确保包含您迄今为止尝试过的内容。至少,在问题中包含堆栈跟踪,并在代码中标记重要的行号。另外,请先尝试简化代码(请参阅SSCCE)。

    【讨论】:

    • 您提到了调试...它是如何工作的?我一直在研究这个话题一段时间,但一无所获。我敢肯定,像您这样出色的老师可以在一秒钟内教给我!非常感谢! :-)
    • @RuchirBaronia 调试器允许您逐行执行程序以查看调用了哪些方法以及如何更改变量。 IDE 应该有一些工具来做到这一点。例如,请参阅vogella.com/tutorials/EclipseDebugging/article.html
    • @RuchirBaronia 您在堆栈跟踪中看到的任何 NullPointerExceptions 周围的方法上设置断点,并根据您的预期检查变量的值。如果您知道某个变量不应该为 null,那么您可以在任何更改该值的代码周围设置断点。您还可以使用条件断点来告诉您值何时发生变化。
    • 我还建议使用静态分析工具,例如 FINDBUGS en.m.wikipedia.org/wiki/FindBugs
    【解决方案4】:

    问题:什么导致NullPointerException (NPE)?

    如您所知,Java 类型分为原始类型booleanint 等)和引用类型。 Java 中的引用类型允许您使用特殊值 null,这是 Java 表示“无对象”的方式。

    每当您的程序尝试使用null 时,就会在运行时抛出NullPointerException,就好像它是一个真正的引用一样。例如,如果你这样写:

    public class Test {
        public static void main(String[] args) {
            String foo = null;
            int length = foo.length();   // HERE
        }
    }
    

    标记为“HERE”的语句将尝试在 null 引用上运行 length() 方法,这将引发 NullPointerException

    您可以通过多种方式使用null 值,从而生成NullPointerException。事实上,您可以null 做的唯一事情是:

    • 将其赋值给引用变量或从引用变量中读取,
    • 将其分配给数组元素或从数组元素中读取(前提是数组引用本身不为空!),
    • 将其作为参数传递或作为结果返回,或者
    • 使用==!= 运算符或instanceof 对其进行测试。

    问题:如何读取 NPE 堆栈跟踪?

    假设我编译运行上面的程序:

    $ javac Test.java 
    $ java Test
    Exception in thread "main" java.lang.NullPointerException
        at Test.main(Test.java:4)
    $
    

    第一观察:编译成功!程序中的问题不是编译错误。这是一个运行时错误。 (某些 IDE 可能会警告您的程序总是会抛出异常……但标准的 javac 编译器不会。)

    第二个观察:当我运行程序时,它会输出两行“gobbledy-gook”。 错了!! 这不是狼吞虎咽。它是一个堆栈跟踪......它提供了重要信息,如果您花时间仔细阅读它,它将帮助您追踪代码中的错误。

    那么让我们看看它是怎么说的:

    Exception in thread "main" java.lang.NullPointerException
    

    堆栈跟踪的第一行告诉你一些事情:

    • 它告诉您抛出异常的 Java 线程的名称。对于一个有一个线程的简单程序(比如这个),它将是“main”。让我们继续...
    • 它告诉你抛出的异常的全名;即java.lang.NullPointerException
    • 如果异常有关联的错误消息,将在异常名称之后输出。 NullPointerException 在这方面是不寻常的,因为它很少有错误消息。

    第二行是诊断 NPE 中最重要的一行。

    at Test.main(Test.java:4)
    

    这告诉我们一些事情:

    • “at Test.main”表示我们在 Test 类的 main 方法中。
    • "Test.java:4" 给出了类的源文件名,它告诉我们发生这种情况的语句在文件的第 4 行。

    如果您计算上面文件中的行数,第 4 行就是我用“HERE”注释标记的行。

    请注意,在更复杂的示例中,NPE 堆栈跟踪中会有很多行。但是您可以确定第二行(第一行“at”行)会告诉您 NPE 被抛出的位置1

    简而言之,堆栈跟踪将明确地告诉我们程序的哪个语句抛出了 NPE。

    另请参阅:What is a stack trace, and how can I use it to debug my application errors?

    1 - 不完全正确。有些东西叫做嵌套异常......

    问题:如何在我的代码中追踪 NPE 异常的原因?

    这是最难的部分。简短的回答是对堆栈跟踪、源代码和相关 API 文档提供的证据进行逻辑推理。

    让我们先用简单的例子(上面)来说明。我们首先查看堆栈跟踪告诉我们发生 NPE 的位置:

    int length = foo.length(); // HERE
    

    这怎么会引发 NPE?

    事实上,只有一种方法:只有当foo 的值为null 时才会发生。然后我们尝试在null 上运行length() 方法,然后......砰!

    但是(我听到你说)如果 NPE 被抛出到 length() 方法调用中怎么办?

    好吧,如果发生这种情况,堆栈跟踪看起来会有所不同。第一个“at”行表示异常是在 java.lang.String 类的某行中引发的,Test.java 的第 4 行将是第二个“at”行。

    那么null 是从哪里来的?在这种情况下,很明显,很明显我们需要做些什么来修复它。 (为foo分配一个非空值。)

    好的,让我们尝试一个稍微复杂一点的例子。这将需要一些逻辑推理

    public class Test {
    
        private static String[] foo = new String[2];
    
        private static int test(String[] bar, int pos) {
            return bar[pos].length();
        }
    
        public static void main(String[] args) {
            int length = test(foo, 1);
        }
    }
    
    $ javac Test.java 
    $ java Test
    Exception in thread "main" java.lang.NullPointerException
        at Test.test(Test.java:6)
        at Test.main(Test.java:10)
    $ 
    

    所以现在我们有两个“at”行。第一个是针对这一行的:

    return args[pos].length();
    

    第二个是针对这一行的:

    int length = test(foo, 1);
        
    

    看看第一行,那怎么会抛出 NPE?有两种方式:

    • 如果bar 的值为null,那么bar[pos] 将抛出一个NPE。
    • 如果bar[pos] 的值为null,则对其调用length() 将引发NPE。

    接下来,我们需要弄清楚哪些场景可以解释实际发生的情况。我们将从探索第一个开始:

    bar 来自哪里?它是test 方法调用的参数,如果我们查看test 是如何被调用的,我们可以看到它来自foo 静态变量。此外,我们可以清楚地看到,我们将foo 初始化为一个非空值。这足以暂时否定这种解释。 (理论上,其他东西可能改变 foonull ...但这不会发生在这里。)

    那么我们的第二种情况呢?好吧,我们可以看到pos1,所以这意味着foo[1] 必须是null。这可能吗?

    确实如此!这就是问题所在。当我们这样初始化时:

    private static String[] foo = new String[2];
    

    我们分配一个String[],其中有两个元素初始化为null。在那之后,我们并没有改变foo的内容……所以foo[1]仍然是null

    在 Android 上呢?

    在 Android 上,追踪 NPE 的直接原因要简单一些。异常消息通常会告诉您正在使用的空引用的(编译时)类型您在抛出 NPE 时尝试调用的方法。这简化了查明直接原因的过程。

    但另一方面,Android 对 NPE 有一些常见的特定于平台的原因。一个很常见的情况是getViewById 意外返回null。我的建议是搜索关于意外null 返回值原因的问答。

    【讨论】:

      【解决方案5】:

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

      TypeA objA;
      

      此时您刚刚声明此对象,但尚未初始化或实例化。并且每当您尝试访问其中的任何属性或方法时,它都会抛出NullPointerException,这是有道理的。

      请参见下面的示例:

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

      【讨论】:

      • 如果我们给 System.out.println(a.length()); // 将抛出 NullPointerException,要跳过它,我们可以使用 try catch 块来处理。谢谢
      【解决方案6】:

      当应用程序在需要对象的情况下尝试使用 null 时,会引发空指针异常。其中包括:

      1. 调用null 对象的实例方法。
      2. 访问或修改null 对象的字段。
      3. null 的长度视为一个数组。
      4. 像数组一样访问或修改null 的槽。
      5. null 视为 Throwable 值。

      应用程序应抛出此类的实例以指示 null 对象的其他非法用途。

      参考:http://docs.oracle.com/javase/8/docs/api/java/lang/NullPointerException.html

      【讨论】:

      • 保持简单,我喜欢这个答案,如果你认为正确,添加这个 - 访问对象的未初始化属性
      • @Emiliano - 简单地访问已初始化的属性不会导致 NPE。这是您>>do
      • 如果您想要更多案例:1) 使用null 作为synchronized 块的目标,2) 使用null 作为switch 的目标,然后取消装箱@ 987654332@.
      【解决方案7】:

      null 指针是指向任何地方的指针。当您取消引用指针p 时,您说“给我存储在“p”中的位置的数据。当pnull 指针时,存储在p 中的位置是nowhere,您重新说“给我'无处'位置的数据”。显然,它不能这样做,所以它会抛出一个null pointer exception

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

      【讨论】:

      • “NULL 指针是不指向任何地方的指针” 我不同意。空指针不指向任何地方,它们指向空值。
      【解决方案8】:

      已经有很多解释来解释它是如何发生的以及如何解决它,但你也应该遵循最佳实践来完全避免NullPointerExceptions。

      另请参阅: A good list of best practices

      我要补充一点,非常重要的是,充分利用 final 修饰符。 Using the "final" modifier whenever applicable in Java

      总结:

      1. 使用final 修饰符强制执行良好的初始化。
      2. 避免在方法中返回 null,例如在适用时返回空集合。
      3. 使用注释@NotNull@Nullable
      4. 快速失败并使用断言来避免在不应为 null 时将 null 对象传播到整个应用程序。
      5. 首先对已知对象使用等于:if("knownObject".equals(unknownObject)
      6. 首选valueOf() 而不是toString()
      7. 使用空安全StringUtils方法StringUtils.isEmpty(null)
      8. 在方法中使用 Java 8 Optional 作为返回值,Optional 类提供了一种表示可选值而不是空引用的解决方案。

      【讨论】:

      • 在 j2ee 项目中,Nullpointer 异常很常见。某些情况下引用变量得到空值。所以您应该正确检查变量初始化。并且在条件语句期间您应该始终检查标志或引用是否包含 null 或不喜欢:- if(flag!=0) { ur code that uses flag }
      • 值得一提的是,一些 IDE(例如 Eclipse)提供基于 customizable 注释的自动无效分析(例如上面列出的@Nullable)并警告潜在错误。也可以基于现有的代码结构推断和生成这样的注释(例如 IntelliJ 可以做到)。
      • 首先应该做的是在使用可空对象之前,你应该检查它是否为空,使用if (obj==null)。如果它是空的,那么你也应该编写代码来处理它。
      • IMO,最好尽可能避免在方法中返回空对象,并在不允许空输入参数时使用注释,以便按照合同减少 'if (obj==null )´ 在代码中并提高代码的可读性。
      • 在你接受这些“最佳实践”作为真理之前阅读这篇文章:satisfice.com/blog/archives/27
      【解决方案9】:

      空指针异常表明您正在使用对象但未对其进行初始化。

      例如,下面是一个将在我们的代码中使用它的学生类。

      public class Student {
      
          private int id;
      
          public int getId() {
              return this.id;
          }
      
          public setId(int newId) {
              this.id = newId;
          }
      }
      

      下面的代码给你一个空指针异常。

      public class School {
      
          Student student;
      
          public School() {
              try {
                  student.getId();
              }
              catch(Exception e) {
                  System.out.println("Null pointer exception");
              }
          }
      }
      

      因为您使用的是student,但是您忘记像在 正确的代码如下所示:

      public class School {
      
          Student student;
      
          public School() {
              try {
                  student = new Student();
                  student.setId(12);
                  student.getId();
              }
              catch(Exception e) {
                  System.out.println("Null pointer exception");
              }
          }
      }
      

      【讨论】:

      • 虽然这是一个很好的例子,但我可以问一下它对所有其他答案尚未涵盖的问题增加了什么?
      • 这里使用“未初始化”这个词是完全不合适的。您显示的示例实际上是“初始化”的,并且它是用 null 初始化的。对于未初始化的变量,编译器会向你抱怨。
      【解决方案10】:

      在 Java 中,一切(不包括原始类型)都是类的形式。

      如果你想使用任何对象,那么你有两个阶段:

      1. 声明
      2. 初始化

      例子:

      • 声明:Object object;
      • 初始化:object = new Object();

      数组概念也一样:

      • 声明:Item item[] = new Item[5];
      • 初始化:item[0] = new Item();

      如果您不提供初始化部分,则会出现 NullPointerException

      【讨论】:

      • 在调用实例的方法时经常会发生NullPointerException。例如,如果您声明了一个引用但没有使其指向任何实例,则在调用其方法时会发生NullPointerException。如:YourClass ref = null; // 或者 ref = anotherRef; // 但 anotherRef 没有指向任何实例 ref.someMethod(); // 它将抛出 NullPointerException。一般这样修复:在调用方法之前,判断引用是否为null。如: if (yourRef != null) { yourRef.someMethod(); }
      • 或者使用异常捕获:如:try { yourRef.someMethod(); } catch (NullPointerException e) { // TODO }
      【解决方案11】:

      Java 中,您声明的所有变量实际上都是对对象(或原语)的“引用”,而不是对象本身。

      当您尝试执行一个对象方法时,引用会要求活动对象执行该方法。但是,如果引用引用的是 NULL(无、零、无效、nada),则该方法无法执行。然后运行时通过抛出 NullPointerException 让您知道这一点。

      您的引用是“指向”null,因此是“Null -> Pointer”。

      对象位于 VM 内存空间中,访问它的唯一方法是使用 this 引用。举个例子:

      public class Some {
          private int id;
          public int getId(){
              return this.id;
          }
          public setId( int newId ) {
              this.id = newId;
          }
      }
      

      在你的代码中的另一个地方:

      Some reference = new Some();    // Point to a new object of type Some()
      Some otherReference = null;     // Initiallly this points to NULL
      
      reference.setId( 1 );           // Execute setId method, now private var id is 1
      
      System.out.println( reference.getId() ); // Prints 1 to the console
      
      otherReference = reference      // Now they both point to the only object.
      
      reference = null;               // "reference" now point to null.
      
      // But "otherReference" still point to the "real" object so this print 1 too...
      System.out.println( otherReference.getId() );
      
      // Guess what will happen
      System.out.println( reference.getId() ); // :S Throws NullPointerException because "reference" is pointing to NULL remember...
      

      这是一件很重要的事情——当不再有对某个对象的引用时(在上面的示例中,referenceotherReference 都指向 null),那么该对象是“不可访问的”。我们无法使用它,因此该对象已准备好进行垃圾回收,并且在某个时候,VM 将释放该对象使用的内存并分配另一个。

      【讨论】:

        【解决方案12】:

        NullPointerException 的另一种情况发生在声明对象数组时,然后立即尝试取消引用其中的元素。

        String[] phrases = new String[10];
        String keyPhrase = "Bird";
        for(String phrase : phrases) {
            System.out.println(phrase.equals(keyPhrase));
        }
        

        如果颠倒比较顺序,可以避免这种特殊的 NPE;即,在保证的非空对象上使用.equals

        数组are initialized to their common initial value内的所有元素;对于任何类型的对象数组,这意味着所有元素都是null

        必须在访问或取消引用它们之前初始化数组中的元素。

        String[] phrases = new String[] {"The bird", "A bird", "My bird", "Bird"};
        String keyPhrase = "Bird";
        for(String phrase : phrases) {
            System.out.println(phrase.equals(keyPhrase));
        }
        

        【讨论】:

        • 在实例级别(不是类级别)对未初始化对象的操作将导致 NullPointerException。操作需要特定于实例。如果操作是在类级别,即在未初始化的对象上调用静态方法,则不会抛出 NullPointerException 异常。即使是原始包装类对象也会抛出 NullPointerException。
        • 1. NullPointerException 是一个 RuntimeException,这意味着程序运行时会出现,编译时不会出现。! :(,但大多数 IDE 都会帮助您发现这一点。2. 尽量减少在赋值语句中使用关键字“null”。:) Reference url:
        • @tomj0101 我完全不清楚你为什么发表这样的评论......但对于你的第二点,Optional 之前的模式是返回 null。关键字很好。知道如何防范它是至关重要的。这提供了一种常见的情况以及缓解它的方法。
        • @Shomu:我什至建议在什么时候抓住它?