【问题标题】:Why NullPointerException? [duplicate]为什么是 NullPointerException? [复制]
【发布时间】:2015-01-05 18:42:32
【问题描述】:

我有一个抽象类和一个派生类。 查看提供的代码:-

public abstract class Parent{
    public Parent(){
        init();
    }

    public abstract void init();    
}



public class Child extends Parent{
    private String mTitle = null;

    public Child(){
        super();
        System.out.println(mTitle.toString());
    }       

    public void init(){
        mTitle = "It' a test";
    }    
}

当我执行上面的代码时,它会在打印 mTitle 的值时抛出 NullPointerException。 如果你检查父类的构造函数中的代码,我调用了抽象方法,它将调用派生类的 init 方法, 在抽象方法中,我将 mTitle 值的值初始化为 ="It's a test";

调用父构造函数后派生类必须调用System.out.println。

如果它是这样做的,那么为什么它会抛出 NullPointerException。

但是,如果我只是离开 mTitle 的分配,它不会抛出异常,如:-

private String mTitle;

如果在调用类的结构时发生变量的初始化,并且我们知道默认情况下全局对象已初始化为空。 但是在这种情况下它不会抛出异常。

【问题讨论】:

  • @1owk3y 显然是一个错字。这甚至不能用extenda 编译,更不用说在运行时抛出NullPointerException。
  • 另外,“Public”在定义类时不是合法关键字。此外,init(): 不是法律声明,您可能想要一个;。请仔细检查您发布的代码是否实际上是您正在运行的代码。你的许多错别字引起了一些怀疑。
  • 你在构造函数中调用了一个可覆盖的方法。这可能会产生意想不到的行为,不应该这样做。延伸阅读:stackoverflow.com/q/3404301/1407656
  • 但是,如果我不会在类中分配 mTitle 的值并简单地写成这样:- private String mTitle;它不会抛出异常。

标签: java exception inheritance abstract


【解决方案1】:

与JLS §12.5 (Creation of New Class Instances) 一样,创建实例时使用以下过程:

  1. 将构造函数的参数分配给此构造函数调用的新创建的参数变量。

  2. 1234563如果该构造函数调用突然完成,则此过程出于相同原因而突然完成;否则,继续第 5 步。
  3. 此构造函数不以显式构造函数调用同一类中的另一个构造函数开始(使用 this)。如果此构造函数用于 Object 以外的类,则此构造函数将以显式或隐式调用超类构造函数开始(使用 super)。使用这五个相同的步骤以递归方式评估超类构造函数调用的参数和过程。如果该构造函数调用突然完成,则此过程出于相同的原因突然完成。否则,继续第 4 步。

  4. 执行该类的实例初始化程序和实例变量初始化程序,将实例变量初始化程序的值分配给相应的实例变量,按照它们在源代码中的文本出现的从左到右的顺序班级。如果执行这些初始化程序中的任何一个导致异常,则不会处理更多初始化程序,并且此过程会突然完成相同的异常。否则,继续第 5 步。

  5. 执行此构造函数的其余部分。如果该执行突然完成,则此过程出于相同原因突然完成。否则,此过程正常完成。

这意味着您对super() 的调用以及对被覆盖的init() 方法的后续调用都已完成在实例变量用null 初始化之前,它会丢弃@987654325 的结果@ 方法并用 null 值覆盖分配给 mTitle 的任何值。

这导致了以下黄金法则:永远不要在构造函数中调用非最终的、非私有的方法!

【讨论】:

    【解决方案2】:

    根据Section 12.5 of the JLS,超类构造函数将在mTitle的初始化程序之前运行,这意味着它将在设置为null之后重新设置为null。

    【讨论】:

      【解决方案3】:

      根据JLS的section 12.5,超类构造函数将在派生类的构造函数之前运行。

      全局变量的初始化是在调用构造函数的时候调用的。 因此,当超类构造函数调用抽象方法并在抽象方法实现中设置 mTitle 值时,它会将第一个它的值设置为 ="it's a test"。 完成超类构造函数后,它将调用派生类构造函数和 当派生类构造函数调用时,它将首先初始化其将 mTitle 值设置为 null 的全局变量。 正如代码中提到的那样

      private String mTitle = null;
      

      但在第二种情况下,mTitle 没有在代码中指定任何值作为提及

      private String mTitle;
      

      所以它将采用我们在实现抽象方法init“it a test”时分配的默认值,因此它不会产生任何异常。

      【讨论】:

        猜你喜欢
        • 2016-09-10
        • 1970-01-01
        • 2011-06-06
        • 1970-01-01
        • 1970-01-01
        • 2020-07-18
        • 1970-01-01
        • 2019-11-01
        • 1970-01-01
        相关资源
        最近更新 更多