再次调用静态初始化程序

8

一旦一个类被加载,是否有办法再次调用静态初始化器?

public class Foo {

    static {
        System.out.println("bar");
    }

}

编辑:

我需要调用静态初始化器,因为我没有编写原始类,并且我需要调用的逻辑是在静态初始化器中实现的。

6个回答

10
将初始化代码放在一个单独的公共静态方法中,这样您就可以从静态初始化程序和其他地方调用它。

我无法修改代码。它在第三方库中,我不打算创建自己的分发版,并将其代码放在常规静态方法中。 :) 我使用的解决方案是将代码复制并粘贴到另一个类中,以便可以在常规静态方法中使用。但我不喜欢这样做。DRY - Kalecser
嗯...那么我的下一个问题是,为什么第三方类在静态初始化器中有逻辑,而你可能想要重新调用它?! - Daniel Earwicker
它将在静态初始化程序中加载和处理XML配置文件,我想重新加载XML。 - Kalecser
静态初始化器有70+行代码。 - Kalecser
唉...我很同情你! :) - Daniel Earwicker

5

如果同一个类被不同的ClassLoader加载多次,那么逻辑将会运行多次。需要注意的是,在这种情况下,它们实际上是不同的类。

通常情况下,这些只是一次性的操作。如果您想要能够多次调用逻辑,请像其他人建议的那样将其放在静态方法中。


1
我试图找到有关类加载器的参考资料,但找不到一个好的。你有吗? - Michael Myers
1
唉,不行。我的知识是从虚拟机规范、Java文档、服务器手册和各种互联网来源拼凑而成的。你可以通过谷歌搜索“developerWorks”和“ClassLoader”来获取更多信息。 - McDowell
这里的答案有一个小的类加载器示例: https://stackoverflow.com/questions/33040829/java-static-initializer-called-twice - KANJICODER

4

我同意Earwicker的回答。只需将静态初始化提取到单独的静态方法中。

public class Foo {

    static {
        Foo.initialize();
    }

    public static void initialize() {
        System.out.println("bar");
    }

}

为什么会遭到负评?能不能请给我点评的人解释一下原因呢? - bruno conde

2
如果你真的想要精确回答你的问题,那么答案是否定的。无法通过反射来调用静态初始化程序或实例初始化程序。
文档清楚地说明:
对于getDeclaredMethod(String name)
如果名称是“<init>”或“<clinit>”,则会引发NoSuchMethodException异常。
对于getDeclaredMethods()
类初始化方法不包含在返回的数组中。
因此,即使通过反射,也无法调用它。

0
你可以尝试扩展包含静态代码的类,然后放入自己的静态初始化器。不太确定是否有效,但是:
public class OldBadLibraryClass {
   static {
      System.out.println("oldBadLibrary static init");
   }
}

//next file

public class MyBetterClass extends OldBadLibraryClass {
   static {
      System.out.println("MyBetterClass init");
   }
}


public class Test {
   public static void main(String[] args) {
      new MyBetterClass();
   }
}

看看上面的内容是否按照你预期的顺序打印出来。在我的机器上,它可以正常工作。

虽然这完全是一种hack方法,而且非常脆弱。最好的方法是修改旧类,添加一个可以被覆盖的init()方法。


0

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接