静态块是否在没有main方法的情况下执行?

今天我给了一个Java测验,有一个问题,如:

静态块甚至在应用程序中没有主方法执行。
真的
2.错

我回答的问题是2. False 。 但是,在检查了我的结果后,我感到困惑,因为根据测验,这是错误的答案。 现在,我用我自己的示例代码重新检查了我的答案,它没有执行任何操作也没有显示任何错误。 这是我的示例代码:

 public class StaticBlockDemo { static { System.out.println("Hello World"); } } 

哪一个是正确的答案? 我正在使用Java 7。

如果将一个System.exit(0)放在static -block的末尾,它将在Java 6及更低版本中运行时没有错误(没有有效的main !)。 这是因为在搜索有效的main方法之前执行static块,因此如果在静态块结束时退出程序,则不会收到任何错误。

但是,这种行为在Java 7中已经改变了; 现在你必须包含一个显式的main ,即使它可能永远不会到达。

在Java 7中,问题的答案是错误的 ,但在Java 6及以下版本中答案确实如此


 public class Test { static { System.out.println("Hello World"); System.exit(0); } } 

Java 6:

你好,世界

Java 7:

错误:在类Test中找不到主要方法,请将main方法定义为:
    public static void main(String [] args)

初始化类时执行静态块。 通常, main类将导致引导类的初始化,但是还有其他方法来引导程序,例如通过VM的本机嵌入API 。

调用类的static main方法会导致其初始化,但许多其他事情也是如此:

  1. 创建该类的实例,
  2. 调用任何其他静态方法,
  3. 读取静态字段(不是最终字段或具有基本类型或字符串以外的类型)。

有关更多详细信息,请参阅JLS第12.4章

以下显示了这一点

 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() {} } } 

运行foo将打印

 Foo initialized Initialized initialized 

它不会打印

 NotInitialized initialized 

因为在执行导致其初始化的程序期间没有做任何事情。

看起来你的类有这种行为,因为它从未被使用,如上面的NotInitialized

投票最多的回答是“大部分”正确,但不完全正确。 请考虑下面的代码,其中类具有main方法和静态方法。 静态方法将在主方法和构造函数之前执行(成功)并生成序列:ABCD – 这可能不像您想象的那样。

 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 "); } } 
 abstract class test extends javafx.application.Application { static { System.out.println(“hello”); System.exit(0); } } 

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

运行使用: java test

这甚至适用于JDK 1.8。 🙂

解释是非常详细的,但我为这个特定问题抽象它首先,类加载器子系统在运行时第一次引用它而不是编译时加载一个类。 所以ClassLoader本身就是java.lang包中的一个类

它的实例被称为classLoader实例,它们加载现在的详细信息,它遵循层次结构,BootStrap ClassLoader位于顶层

请注意,BootStrap类加载器本身是ClassLoader的一个实例。

更多这些实例还执行validation,准备,解析符号引用以保持简单,它执行java程序的动态链接。

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

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

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

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

一旦加载了类,静态块就会在类加载器子系统的初始化阶段执行。

因为我已经告诉它的编译器扮演插入该字段的角色。 并注意,未找到main方法是运行时错误,因此编译器不对此负责,而是JVM。

从java 7开始搜索main方法,如果我们没有在运行时得到这个错误,但是在java 6及更早版本中,当类加载发生时,静态块被激活,然后搜索找到主要方法但是如果我们提供System.exit(0); 在块中它甚至在搜索之前终止程序因此我们没有任何错误

虽然在java 7中探测main方法是在执行静态块之前完成的,静态块本身的执行依赖于main方法的成功发现。尽管程序的执行顺序是程序与java 6及更早版本相同版。

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

同样重要的是要注意我们不能在任何静态或非静态范围内嵌套静态块,因为这个块只有更高的封闭范围才能达到类的范围。

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

在java 8中,如果没有显式编写main方法,则无法运行程序。 从这个角度来看,答案是假的。 没有main方法就不执行静态块。下面是一段显示初始化顺序的代码。(静态块==> main ==>初始化块==>构造函数)

 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(); } 

在静态块中
在主要方法
在初始化块中
在const