关于java:静态块是否会在没有main方法的情况下执行?

Will a static block execute without the main method?

论坛上有个问题,

The static block even executed without main method in application program.
1. True
2. False

我以2. False的身份回答了这个问题,并在我的机器上尝试了下面的代码。它没有执行任何操作,也没有显示任何错误。

1
2
3
4
5
public class StaticBlockDemo {
    static {
        System.out.println("Hello World");
    }
}

那么,正确的答案是什么?顺便说一下,我使用的是Java 7。


如果你在EDOCX1〕〔1〕的末尾输入一个System.exit(0),它会在Java 6和下游(没有有效的EDOCX1〕〔2〕中运行。这是因为在一个有效的main之前Block是被执行的,方法是寻找,如果在静态块的末端存在程序,你将不会收到错误。

然而,这一行为在Java 7中发生了变化;现在你必须包括一个main的解释,即使它可能永远不会实现。

In Java 7,the answer to the question is false,but in Java 6 and below the answer is indeed true.

1
2
3
4
5
6
public class Test {
    static {
        System.out.println("Hello World");
        System.exit(0);
    }
}

爪哇6号

ZZU1

Java 7:

1
2
Error: Main method not found in class Test, please define the main method as:
   public static void main(String[] args)


当一个类别被初始化时,静态块执行。正常情况下,班级会引发靴子班的初始化,但也有其他方法来增加一个程序,例如通过VM的本地嵌入式API。

一类起因的初始化方法,但要做许多其他的事情:

  • Creating an instance of that class,
  • 呼唤其他静态方法
  • 读一个静态场(这不是最终的,也不是有其他类型,而不是原始类型或字符串)。
  • For more detail see the JLS chapter 12.4

    下面的展示在行动中

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    public class Foo {
      static { System.out.println("Foo initialized"); }

      public static void main(String... argv) {
        Initialized.callingThisCausesClassInitialization();
      }

      static class Initialized {
        static { System.out.println("Initialized initialized"); }
        static void callingThisCausesClassInitialization() {}
      }

      static class NotInitialized {
        static { System.out.println("NotInitialized initialized"); }
        static void callingThisCausesClassInitialization() {}
      }
    }

    运行,运行,运行

    1
    2
    Foo initialized
    Initialized initialized

    不会打印

    1
    NotInitialized initialized

    因为在执行该方案期间没有做任何事情,而该方案的初始化是由该方案引起的。

    它看上去像你的班级,因为它从来没有使用过,就像NotInitialized


    1
    2
    3
    4
    5
    6
    abstract class test extends javafx.application.Application {
        static {
            System.out.println("hello");
            System.exit(0);
        }
    }

    编译使用:javac -source 1.6 test.java

    运行使用:java test

    这甚至适用于JDK1.8。???


    在Java 8中,不显式地编写主方法就不能运行程序。从这个角度来说,答案是错误的。没有main方法就不能执行静态块。下面是一段显示初始化顺序的代码。(static block==>main==>initialization block==>constructor)

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

    static{
        System.out.println("in static block");
    }


    {
        System.out.println("in initialization block");
    }

    public StaticBlock(){
        System.out.println("in const");
    }

    public static void main(String[] args) {
            System.out.println("in main method");
            StaticBlock block=new StaticBlock();
    }

    静态块主法在初始化块中在康斯特


    最正确的答案是最正确的,但并非完全正确。考虑在班级有主要方法和静态方法的下面的代码。静态方法将在主要方法之前执行(成功地)和制造商并产生序列:B C-D,这不是你可能想到的。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    public class Sequence {
        Sequence() {
            System.out.print("c");
        }
        {
            System.out.print("B");
        }
        public static void main(String[] args) {
            new Sequence().go();
        }
        void go() {
            System.out.print("D");
        }
        static{
            System.out.print("A");
        }
    }


    解释很详细,但我是为这个具体问题抽象出来的。首先,类装入器子系统在运行时第一次引用类,而不是在编译时加载类。所以类加载器本身就是java.lang包中的一个类,并且

    它的实例称为加载类的类加载器实例现在详细介绍一下,它遵循一个层次结构,引导类加载器位于顶部。

    注意,引导类加载器本身是类加载器的一个实例。

    更重要的是,这些实例还执行验证、准备、解析符号引用以保持它的简单性,它执行Java程序的动态链接。

    现在,当编译器编译.java文件时,它会插入一个类型类的公共静态最终字段。您可以在java.lang.class obj=name_your_class.class中访问它。

    它包含一个方法getClassLoader,它告诉类加载器实例加载了这个类。

    仅通过使用此信息,类加载器才能知道要加载的类的名称,即它的完全限定名(package.class)

    现在,在搜索本机文件系统中的文件并加载它之前它检查它的父实例是否已经加载了该文件以及此检查是否会一直传播到顶级bootclassloader。只有当它们都没有加载它时,才只有那个实例加载那个类文件。在这种情况下,这些事情是如何发生的细节无关紧要。

    一旦类被加载,静态块将在类加载子系统的初始化阶段执行。

    因为我已经告诉过它的编译器扮演着插入那个字段的角色。请注意,找不到主方法是一个运行时错误,因此编译器对此不负责,而应该是JVM。

    在Java 7之前,先搜索主方法,如果没有,则在运行时得到此错误。但是在Java 6和早期版本中,当类加载本身发生时,静态块被执行,然后搜索主方法,但是如果提供Surviv.Exchange(0);在块中,即使在进行搜索之前,它也会终止程序,因此我们没有任何错误。

    虽然在Java 7中对主方法的探测是在执行静态块之前完成的,但是静态块本身的执行依赖于主方法的成功发现。即使程序的执行顺序是与Java 6和早期版本相同的。

    更详细地说,要放在堆栈本身上的第一个元素应该是主线程。我们知道执行控制是如何流动的,更重要的是要注意,静态块即使包含其块的局部变量,也不会作为激活记录放在堆栈上,而是放在方法区域上。因此,从Java 7中,JVM检查堆栈上主线程记录的存在,然后将控制权赋予静态块,然后在静态块中按顺序执行所有静态块。相反,它在Java 6和早期版本中出现了相反的情况。

    另外需要注意的是,我们不能在任何静态或非静态范围内嵌套静态块,因为该块的封闭范围只有类的更高。

    我甚至知道理解它有点困难,但是阅读这个答案肯定会提供对静态块的良好、准确和深入的理解。