Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/329.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_Static Initializer - Fatal编程技术网

Java中静态/实例初始值设定项块的运行顺序是什么?

Java中静态/实例初始值设定项块的运行顺序是什么?,java,static-initializer,Java,Static Initializer,假设一个项目包含几个类,每个类都有一个静态初始值设定项块。这些区块的运行顺序是什么?我知道在一个类中,这些块是按照它们在代码中出现的顺序运行的。我已经读到,这在不同的类中是相同的,但是我编写的一些示例代码不同意这一点。我使用了以下代码: package pkg; public class LoadTest { public static void main(String[] args) { System.out.println("START"); new

假设一个项目包含几个类,每个类都有一个静态初始值设定项块。这些区块的运行顺序是什么?我知道在一个类中,这些块是按照它们在代码中出现的顺序运行的。我已经读到,这在不同的类中是相同的,但是我编写的一些示例代码不同意这一点。我使用了以下代码:

package pkg;

public class LoadTest {
    public static void main(String[] args) {
        System.out.println("START");
        new Child();
        System.out.println("END");
    }
}

class Parent extends Grandparent {
    // Instance init block
    {
        System.out.println("instance - parent");
    }

    // Constructor
    public Parent() {
        System.out.println("constructor - parent");
    }

    // Static init block
    static {
        System.out.println("static - parent");
    }
}

class Grandparent {
    // Static init block
    static {
        System.out.println("static - grandparent");
    }

    // Instance init block
    {
        System.out.println("instance - grandparent");
    }

    // Constructor
    public Grandparent() {
        System.out.println("constructor - grandparent");
    }
}

class Child extends Parent {
    // Constructor
    public Child() {
        System.out.println("constructor - child");
    }

    // Static init block
    static {
        System.out.println("static - child");
    }

    // Instance init block
    {
        System.out.println("instance - child");
    }
}
得到了这个输出:

开始
静态-祖父母
静态-父级
静态-子级
实例-祖父母
建造师-祖父母
实例-父级
构造函数-父级
实例-子对象
构造函数-子级
结束

显而易见的答案是,父母的积木比孩子的积木早,但这可能只是巧合,如果两个班级不在同一层次结构中,那就没什么帮助了

编辑:

我修改了示例代码,将其添加到LoadTest.java中:

class IAmAClassThatIsNeverUsed {
    // Constructor
    public IAmAClassThatIsNeverUsed() {
        System.out.println("constructor - IAACTINU");
    }

    // Instance init block
    {
        System.out.println("instance - IAACTINU");
    }

    // Static init block
    static {
        System.out.println("static - IAACTINU");
    }
}

正如类名所暗示的,我从未在任何地方引用过新类。新程序产生了与旧程序相同的输出。

第一次访问类时,会运行该类的静态初始值设定项,以创建实例或访问静态方法或字段


因此,对于多个类,这完全取决于运行代码以使这些类加载。

当第一次访问类时,会运行该类的静态初始值设定项,以创建实例或访问静态方法或字段


因此,对于多个类,这完全取决于运行的代码,以使这些类得到加载。

请参阅的第12.4节和第12.5节,他们详细介绍了所有这些(12.4用于静态变量,12.5用于实例变量)

对于静态初始化(第12.4节):

类或接口类型T将在第一次出现以下任一情况之前立即初始化:

  • T是一个类,并且创建了T的一个实例
  • T是一个类,调用由T声明的静态方法
  • 分配了一个由T声明的静态字段
  • 使用T声明的静态字段,该字段不是常量变量(§4.12.4)
  • T是一个顶级类(§7.6),执行嵌套在T(§8.1.3)中的assert语句(§14.10)

(和几个weasel word子句)

参见的第12.4节和第12.5节,它们详细介绍了所有这些(12.4表示静态变量,12.5表示实例变量)

对于静态初始化(第12.4节):

类或接口类型T将在第一次出现以下任一情况之前立即初始化:

  • T是一个类,并且创建了T的一个实例
  • T是一个类,调用由T声明的静态方法
  • 分配了一个由T声明的静态字段
  • 使用T声明的静态字段,该字段不是常量变量(§4.12.4)
  • T是一个顶级类(§7.6),执行嵌套在T(§8.1.3)中的assert语句(§14.10)

(还有几个狡猾的词语从句)

基思和克里斯的答案都很好,我只是为我的具体问题补充了一些细节

静态init块按其类初始化的顺序运行。那么,这是什么顺序?根据JLS 12.4.1:

类或接口类型T将在第一次出现以下任一情况之前立即初始化:

  • T是一个类,并且创建了T的一个实例
  • T是一个类,调用由T声明的静态方法
  • 分配了一个由T声明的静态字段
  • 使用T声明的静态字段,该字段不是常量变量(§4.12.4)
  • T是一个顶级类,执行嵌套在T中的assert语句(§14.10)
在类和包java.lang.reflect中调用某些反射方法也会导致类或接口初始化。在任何其他情况下,类或接口都不会初始化

为了举例说明,下面是示例中发生的情况的演练:

  • 进入主
  • 打印“开始”
  • 尝试创建子实例的第一个实例,这需要初始化子实例
  • 尝试初始化子级会导致父级初始化
  • 尝试初始化父级会导致祖父母初始化
  • 在祖父母初始化开始时,祖父母的静态初始化块运行
  • 从技术上讲,对象由于是祖父母的父母而在初始化链中拥有最后发言权,但它没有任何贡献
  • 祖父母的静态初始化块结束后,程序返回到父母的静态初始化块
  • 在父级的静态初始化块结束后,程序返回到子级的静态初始化块
  • 此时,子级已初始化,因此它的构造函数可以继续进行
  • 由于从未被引用的IAMACLASSTHATEISNEVERUSED从未被引用,因此它的任何代码都不会运行,包括静态初始值设定项块
  • 本演练的其余部分不涉及静态初始值设定项,仅为完整性考虑
  • 子级构造函数隐式调用super()(即父级构造函数)
  • 父级的构造函数隐式调用super()(即祖父母的构造函数)
  • 祖父母的构造函数也这样做,但没有效果(同样,对象没有任何贡献)
  • 在祖父母的构造函数调用super()之后,祖父母的实例初始值设定项块立即出现
  • 祖父母的构造函数的其余部分运行,构造函数终止
  • 该程序可追溯到
    static{
    i=1;
    i=2;
    }
    
    class Super {
        public static int i=10;
    }
    class Sub extends Super {
        static {
            system.out.println("Static block called");
        }
    }
    class Test {
        public static void main (String [] args) {
            system.out.println(Sub.i);
        } 
    }
    
    class A {
      public A() { 
        // 2
      }
    }
    
    class B extends A{
      static char x = 'x'; // 0
      char y = 'y'; // 3
      public B() { 
        // 4
      }
    
      public static void main(String[] args) {
        new B(); // 1
      }
    }