关于Java:在默认构造函数之前执行的方法

Java - Method executed prior to Default Constructor

本问题已经有最佳答案,请猛点这里访问。

我正在学习Java,偶然遇到了下面的代码,其中在方法之后执行默认构造函数。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public class ChkCons {

    int var = getVal();

    ChkCons() {
        System.out.println("I'm Default Constructor.");
    }

    public int getVal() {
        System.out.println("I'm in Method.");
        return 10;
    }

    public static void main(String[] args) {

        ChkCons c = new ChkCons();

    }

}

输出:

1
2
I'm in Method.
I'
m Default Constructor.

有人能解释一下为什么会这样吗?

谢谢。


实例变量初始化表达式(如int var = getVal();)在执行超级类构造函数之后,但在执行当前类构造函数的主体之前进行计算。

因此,在执行ChkCons构造函数的主体之前调用getVal()


在方法之前调用构造函数。方法的执行发生在对象创建过程中对实例变量进行计算的部分之后。从下面的代码可以更好地理解这一点。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
class SuperClass{
    SuperClass(){
        System.out.println("Super constructor");
    }
}
public class ChkCons extends SuperClass{

    int var = getVal();

    ChkCons() {
        System.out.println("I'm Default Constructor.");
    }

    public int getVal() {
        System.out.println("I'm in Method.");
        return 10;
    }

    public static void main(String[] args) {

        ChkCons c = new ChkCons();

    }

}

以上代码输出如下

1
2
3
Super constructor
I'm in Method.
I'
m Default Constructor.

在这里,编译器自动添加super();作为ChkCons()构造函数中的第一条语句,因此在getVal()方法之前调用它。


我们可以参考以下有关初始化实例变量的Oracle文档(重点是我的):

Initializing Instance Members

Normally, you would put code to initialize an instance variable in a
constructor. There are two alternatives to using a constructor to
initialize instance variables: initializer blocks and final methods.

Initializer blocks for instance variables look just like static
initializer blocks, but without the static keyword:

{
// whatever code is needed for initialization goes here }

> The Java compiler copies initializer blocks into every constructor.
Therefore, this approach can be used to share a block of code between
multiple constructors.

A final method cannot be overridden in a subclass. This is discussed
in the lesson on interfaces and inheritance. Here is an example of
using a final method for initializing an instance variable:

1
2
3
4
5
6
7
8
class Whatever {
private varType myVar = initializeInstanceVariable();

protected final varType initializeInstanceVariable() {

    // initialization code goes here
}
}

https://docs.oracle.com/javase/tutorial/java/javaoo/initial.html


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
public class InitializerIndex {

    public InitializerIndex() {
        // TODO Auto-generated constructor stub
        System.out.println("Default Constructor");
    }

    static {

        System.out.println("Static Block one");
    }

    {
        System.out.println("Init one");
    }

    void letsRoll() {

    }

    public static void main(String[] args) {
        new InitializerIndex().letsRoll();
        new InitializerIndex().letsRoll();
    }

    {
        System.out.println("Init Two");
    }

    static {
        System.out.println("Static Block two");
    }

}

将具有以下输出:

1
2
3
4
5
6
7
8
Static Block one
Static Block two
Init one
Init Two
Default Constructor
Init one
Init Two
Default Constructor

首先加载所有静态内容,然后加载实例内容。静态内容只加载一次。

即使创建了两个对象,也只有在创建第一个对象时才调用静态块。

另外,在对象创建时或在构造函数中,如果要使用这样的方法

1
 int var = getVal();

您应该使用静态方法。


每当创建类实例时,首先初始化实例变量,然后执行构造函数

REF:在Java中运行构造函数代码之前,字段是否已初始化?


这是因为您正在使用int var = getVal();将方法初始化为字段,所以它将在构造函数调用之前执行。静态block具有第一优先权,它在类加载期间执行。