当前位置: 首页 > 知识库问答 >
问题:

哪个先跑?实例变量或超级构造函数的默认值?

戴鸿羽
2023-03-14

根据SCJP6(第507页),我发现在超类构造函数完成之前,实例变量被分配了默认值,我在调试模式下尝试了一个例子,但我看到超级承包商在实例变量获得默认值之前运行,有人能向我解释一下吗?

我举了一个例子,以防有人想试试:

package courseExercise;

class test {
    test() {
        System.out.println("Super Constructor run");
    }
}

public class Init extends test {

    private Integer i = 6;
    private int j = 8;

    Init(int x) {
        super();
        System.out.println("1-arg const");
    }

    Init() {
        System.out.println("no-arg const");
    }

    static {
        System.out.println("1st static init");
    }
    public static int d = 10;
    {
        System.out.println("1st instance init");
    }
    {
        System.out.println("2nd instance init");
    }
    static {
        System.out.println("2nd static init");
    }

    public static void main(String[] args) {
        new Init();
        new Init(7);
    }
}

共有1个答案

东郭远航
2023-03-14

JLS 12.5中规定了初始化顺序:

  1. 首先,为新对象分配内存
  2. 然后对象中的所有实例变量(包括在这个类及其所有超类中定义的变量)都初始化为默认值
  3. 最后,调用构造函数。

规范的相关部分是:

......

如果没有足够的可用空间为对象分配内存,则类实例的创建会突然完成,并出现OutOfMemoryError。否则,新对象中的所有实例变量(包括在超类中声明的实例变量)都将初始化为其默认值(§4.12.5)。

在返回对新创建对象的引用作为结果之前,将使用以下过程处理指示的构造函数以初始化新对象:

......

这就是你不应该从构造函数中调用非final方法的原因之一:该方法可能会被子类覆盖,在这种情况下,该方法将在子类有机会设置该方法可能需要的状态之前被调用。考虑一下这个例子:

public class Super {
  private final int superValue;

  protected Super() {
    superValue = getSuperValue();
  }

  protected int getSuperValue() {
    return 1;
  }

  @Override
  public String toString() {
    return Integer.toString(superValue);
  }
}

public class Sub extends Super {
  private final int superValueOverride;

  public Sub(int value) {
    this.superValueOverride = value;
  }

  @Override
  protected int getSuperValue() {
    return superValueOverride;
  }

  public static void main(String[] args) {
    Super s = new Sub(2);
    System.out.println(s);
  }
} 

它看起来像是s.superValue应该是2,对吗?毕竟,Sub覆盖getSuperValue()以返回superValueOverride的值,该值初始化为2。但是在初始化任何Sub字段之前(除了它们的默认值),就会调用该方法,因此s.superValue实际上是0(superValueOverride的默认值)。

这甚至更奇怪,因为superValueOverridefinal,但它似乎改变了它的值!当Super调用getSuperValue()时,它是0,只有在Super构造函数完成后,它才被赋予其最终值2(或传递给构造函数的任何值)。

 类似资料:
  • 问题内容: 根据SCJP6(页507),我发现在超类构造函数完成之前为实例变量分配了默认值,我在Debugg模式下尝试了一个示例,但是我看到超级承包商在实例变量获得其默认值之前运行,可以有人解释吗?那对我呢? 我使用的示例,以防有人要尝试: 问题答案: 初始化序列在JLS 12.5中 指定: 首先,为新对象分配内存 然后,将对象中的所有实例变量(包括在此类及其所有超类中定义的实例变量)初始化为其默

  • 问题内容: 我有一些简单的Java代码,其结构与此类似: 我将有很多的子类,每个子类以自己的方式(模板方法模式)实现方法。 这很好用,但是我不喜欢子类中有多余的构造函数。输入更多,难以维护。如果要更改构造函数的方法签名,则必须更改所有子类。 当我从子类中删除构造函数时,出现此编译时错误: 我想做的事可能吗? 问题答案: 你会收到此错误,因为没有构造函数的类具有默认构造函数,该构造函数没有参数,并且

  • 问题内容: 默认构造函数到底是什么?你能告诉我以下哪个是默认构造函数,它与其他构造函数有何不同? 问题答案: 他们都不是。如果定义,则不是默认值。 除非你定义另一个构造函数,否则默认构造函数是自动生成的无参数构造函数。任何未初始化的字段都将设置为其默认值。对于你的榜样,它看起来像这样假设的类型String,int以及int,那类本身是公共的: 这与 完全没有构造函数。但是,如果定义至少一个构造函数

  • 我的问题是关于OOP(C)中的构造函数。当我在一个类中将默认构造函数定义为private,并且在main中将该类的一个对象初始化为default时,就会出现默认构造函数不可访问的错误。这很好。但我也在Public部分中使用默认参数构造函数,当我再次在main中初始化对象时,就会出现对函数重载的不明确调用。所以我的问题是,如果不能从main访问私有构造函数,那么编译器应该调用公共部分中的构造函数,这

  • 问题内容: 我遇到这个错误: 不知道为什么我得到那个例外 我正在运行 主要 这是我的 课 当我保存,更新和删除它时,它可以正常工作,所以我不知道我在做什么错 EDIT1 在这里是principal.Cliente 问题答案: 我可以说缺少默认构造函数,

  • Spring靴和jpa给出了错误 项目的github链接https://github.com/dishankgoyal/springsBoot/tree/master/faculty_project