什么时候执行该类的静态块?


73

我有2个罐子,我们称它们为a.jar和b.jar。

b.jar取决于a.jar。

在a.jar中,我定义了一个类,我们称它为StaticClass。在StaticClass中,我定义了一个静态块,调用了一个名为“ init”的方法:

public class StaticClass {
  static {
    init();
  } 

  public void static init () {
    // do some initialization here
  }
}

在b.jar中,我有一个main,因此在main中,我希望已经调用了init()方法,但实际上没有。我怀疑这是因为jvm尚未加载StaticClass,谁能告诉我

  1. 我的结论正确吗?
  2. 是什么触发了jvm加载类?
  3. 如何获得自动执行的静态块?

谢谢


3
您将不得不在其他地方使用StaticClass,以便对其进行加载和初始化。
克里斯(Kris)

3
看来可以回答您的问题。
Andreas Baus

Answers:


94

是的,你是对的。静态初始化块在JVM(具体来说是类加载器)加载时运行StaticClass(在第一次在代码中引用它时)运行。

您可以通过显式调用来强制调用此方法 StaticClass.init()这比依赖JVM更可取。

您也可以尝试使用Class.forName(String)强制JVM加载类并调用其静态块。


“不是第一次在代码中引用它”。访问静态基本类型似乎并不会触发静态块。

7
“当JVM加载StaticClass` ---不正确,类加载是从类的初始化不同的静态初始化块运行。
马尔科Topolnik

4
“第一次在代码中引用它时发生” ---错误,实现可以自由决定何时加载该类。引用该类只是绝对必须加载的最后期限
Marko Topolnik '16

1
@MarkoTopolnik是正确的。错误声明“在JVM加载StaticClass时运行静态初始化块”。静态块在类初始化期间执行。“比依赖JVM更可取”是另一个令人困惑的语句,在StaticClass.init()的情况下,与“依赖”无关,它只是一个静态方法调用。
沙芬·马哈茂德

@hthserhs在期间内联了公共静态最终基本类型和字符串javac。因此,从JVM的角度来看,实际上没有“访问”。结果,行为是可以理解的。我只想添加一些上下文。你说的肯定是正确的。
Haozhun

7

是的,您是对的,因为您没有使用StaticClass它,因此vm不会加载它,因此init()永远不会执行。

对于第二个问题,您可能必须努力研究并扫描所有可用的类并加载它们。

https://stackoverflow.com/a/3223019/393657


+1提示有关扫描所有类并自动初始化它们的提示。在应该自动执行静态初始化程序的类上使用标记接口/注释(或任何其他定义的静态方法)可能会有所帮助。如链接线程中所述:Google Reflections可能是一种无需太多麻烦的方式。
Thomas

5

首先,类加载不同于类初始化。对于从Java语言规范中寻求解释的任何人,何时执行静态块-就是这样。

JLS§8.7说:

在初始化类时,将执行在类中声明的静态初始化器(第12.4.2节)。

那么初始化是什么意思呢?让我们参考JLS§12.4.2。这描述了详细的初始化过程。但是,此处JLS§12.4.1可能更合适。它说:

类或接口类型T将在以下任何一种首次出现之前立即初始化:
  • T是一个类,并创建T的实例。
  • T是一个类,并调用T声明的静态方法。
  • 分配由T声明的静态字段。
  • 使用由T声明的静态字段,并且该字段不是常量变量(第4.12.4节)。
  • T是顶级类(第7.6节),并执行词法嵌套在T中的断言语句(第14.10节)(第8.1.3节)。
  • 因此,要使静态初始化程序块自动执行,必须强制执行这些选项之一。


    我想知道我们是否可以假设:当在已经运行的代码中通过名称引用类时,将初始化该类。
    Pawel Dubiel19年

    4

    没错,最简单的方法是访问该类,例如执行

    StaticClass.class.newInstance();

    或在您的主要方法中尊重这一点的东西。这将确保类由类加载器加载。


    3

    StaticClass引用您的类(我想)时,将执行静态代码。

    因此,如果你创建一个应当执行新实例StaticClass,或者如果你调用它的静态方法之一



    0

    是的,在加载类时将执行静态初始化器。当您首次在类加载上下文中访问该类时,通常会发生这种情况。


    0

    在b.jar中,主要方法类应扩展StaticClass,然后自动调用static块和init()


    -2

    添加更多:

    当jvm加载类时,将执行static块。

    在您的示例中,您可以通过实例化类来调用init()StaticClass的方法

    像StaticClass staticClass = new StaticClass();

    要么

    StaticClass.class.newInstance(); 这是更偏爱的


    3
    “这更可取”为什么?
    user207421
    By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
    Licensed under cc by-sa 3.0 with attribution required.