Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/354.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
JAVA初始化块_Java - Fatal编程技术网

JAVA初始化块

JAVA初始化块,java,Java,正如一些来源所说,Java实例初始化块在创建实例时或在构造函数之前执行。但想象一下这种情况: public class Foo { { System.out.println("Foo init"); } public Foo() { { System.out.println("Foo constr"); } } } public class Main extends Foo {

正如一些来源所说,Java实例初始化块在创建实例时或在构造函数之前执行。但想象一下这种情况:

public class Foo {

    {
        System.out.println("Foo init");
    }

    public Foo()
    {

        {
            System.out.println("Foo constr");
        }
    }
}

public class Main extends Foo {

    {
        System.out.println("Main init");
    }

    public Main()
    {

        {
            System.out.println("Main constr");
        }
    }

    public static void main(String[] args) {
        new Main();
    }
}
输出如预测:

Foo init
Foo constr
Main init
Main constr
Foo init
Foo constr
Main init
Main constr
所以我的问题是-什么是实例初始化块的正确定义,因为它显然不是在构造函数之前执行的,因为输出应该是

Main init
Foo init
Foo constr
Main constr

因为主构造函数是在调用super之前调用的,主初始化块应该是第一个

否。初始化块直接复制到构造函数中。显然,这里面也隐含着一种超能力。所以你的例子变成了

public class Foo {
  public Foo()
  {
    {System.out.println("Foo init");} // initializer.
    {System.out.println("Foo constr");}
  }
}

public class Main extends Foo {
  public Main()
  {  
    super(); // super constructor.
    {System.out.println("Main init");} // initializer.
    {System.out.println("Main constr");}
  }
  public static void main(String[] args) {
    new Main();
  }
}
这就解释了你观察到的


否。初始化块直接复制到构造函数中。显然,这里面也隐含着一种超能力。所以你的例子变成了

public class Foo {
  public Foo()
  {
    {System.out.println("Foo init");} // initializer.
    {System.out.println("Foo constr");}
  }
}

public class Main extends Foo {
  public Main()
  {  
    super(); // super constructor.
    {System.out.println("Main init");} // initializer.
    {System.out.println("Main constr");}
  }
  public static void main(String[] args) {
    new Main();
  }
}
这就解释了你观察到的

上述状态将首先转到Main。但在执行任何主要操作之前,都会调用super。所以,Foo被称为。现在,在Foo中进行检查以查看实例初始化块。所以,你得到了。Foo init。接下来执行Foo中的语句。所以,你得到了-Foo constr。接下来,控件返回到Main,Main现在检查Main类是否存在初始化块。所以,主初始化被打印。。然后,打印Main的其他语句。这个定义是正确的。。谅解。。好取决于你怎么看


上述状态将首先转到Main。但在执行任何主要操作之前,都会调用super。所以,Foo被称为。现在,在Foo中进行检查以查看实例初始化块。所以,你得到了。Foo init。接下来执行Foo中的语句。所以,你得到了-Foo constr。接下来,控件返回到Main,Main现在检查Main类是否存在初始化块。所以,主初始化被打印。。然后,打印Main的其他语句。这个定义是正确的。。谅解。。好取决于你怎么看…

最后一句话不正确。Main在Foo之后执行,因为类构造函数是在其超级构造函数完成之后执行的。
有关更多详细信息,请参见哪个处理隐式和显式超级构造函数调用。

最后一条语句不正确。Main在Foo之后执行,因为类构造函数是在其超级构造函数完成之后执行的。
有关更多详细信息,请参见哪个处理隐式和显式超级构造函数调用。

编译器会将代码转换为如下内容:

public class Main extends Foo {
  void _init()
  {System.out.println("Main init");}

  public Main()
  {
    super();
    _init();
    {System.out.println("Main constr");}
  }

}
主要规则是:

在当前类的任何初始化代码之前调用super 在构造函数主体之前调用初始值设定项块
编译器会将代码转换为如下内容:

public class Main extends Foo {
  void _init()
  {System.out.println("Main init");}

  public Main()
  {
    super();
    _init();
    {System.out.println("Main constr");}
  }

}
主要规则是:

在当前类的任何初始化代码之前调用super 在构造函数主体之前调用初始值设定项块 JLS中有一个解释,但让我提炼出最关键的部分:

初始化类的过程取决于JVM的实现。 如果超类尚未初始化,则在其子类步骤7之前初始化该超类。 评估所有静态初始值设定项和字段,就像它们是文本顺序中的单个块一样。最后一部分很重要;这意味着首先看到的是先初始化的。 这就是为什么您会看到这样的行为-因为Main是Foo的子类,它还没有初始化,所以它的静态块在那一刻没有被计算

因此,Main的构造函数直到Foo的构造函数之后才执行,因为子类中有。JLS中有一个解释,但让我提取最关键的部分:

初始化类的过程取决于JVM的实现。 如果超类尚未初始化,则在其子类步骤7之前初始化该超类。 评估所有静态初始值设定项和字段,就像它们是文本顺序中的单个块一样。最后一部分很重要;这意味着首先看到的是先初始化的。 这就是为什么您会看到这样的行为-因为Main是Foo的子类,它还没有初始化,所以它的静态块在那一刻没有被计算


因此,Main的构造函数直到Foo的构造函数之后才执行,因为子类中有。请参见此代码的内部工作方式:

class Foo {

    {System.out.println("Foo init");}

    public Foo()
    {

        {System.out.println("Foo constr");}
    }
}



class Main extends Foo {

    {System.out.println("Main init");}

    public Main()
    {

        {System.out.println("Main constr");}
    }
    public static void main(String[] args) {

        new Main();
    }
}
步骤1:JVM调用main类的main方法

第2步:构造函数Main有内部super,如果您不使用它,它由JVM提供,因此super将调用super类构造函数,即super类的Foo

步骤3:现在,在调用超类的Foo之前,JVM将检查是否存在任何IIB,即实例初始化块,因此,在打印Foo constr之前,将先打印Foo init

目前为止的输出为:

Foo init 
Foo constr
步骤4:我们的控件返回到当前构造函数,然后在 e执行当前Constructor JVM将调用IIB,即实例初始化块,并将打印Main init。最后是主施工图

因此,最后的结论是:

Foo init
Foo constr
Main init
Main constr
实际上,任何构造函数的第一次调用总是Super或this。
您正在使用new Main创建新对象;当然,这将调用构造函数,构造函数总是被调用来初始化对象。

查看此代码在内部的工作方式:

class Foo {

    {System.out.println("Foo init");}

    public Foo()
    {

        {System.out.println("Foo constr");}
    }
}



class Main extends Foo {

    {System.out.println("Main init");}

    public Main()
    {

        {System.out.println("Main constr");}
    }
    public static void main(String[] args) {

        new Main();
    }
}
步骤1:JVM调用main类的main方法

第2步:构造函数Main有内部super,如果您不使用它,它由JVM提供,因此super将调用super类构造函数,即super类的Foo

步骤3:现在,在调用超类的Foo之前,JVM将检查是否存在任何IIB,即实例初始化块,因此,在打印Foo constr之前,将先打印Foo init

目前为止的输出为:

Foo init 
Foo constr
第4步:我们的控制返回到当前构造函数,在执行之前,当前构造函数JVM将调用IIB,即实例初始化块,并将打印Main init。最后是主施工图

因此,最后的结论是:

Foo init
Foo constr
Main init
Main constr
实际上,任何构造函数的第一次调用总是Super或this。
您正在使用new Main创建新对象;当然,这将调用构造函数,构造函数总是被调用来初始化对象。

您可以看到仅使用Static with instance initialization块在输出中的差异。您可以看到仅使用Static with instance initialization块在输出中的差异。