6

So, as an example I have this JNI code:

/** This literally does nothing. It's purpose is to call the static initializer early to detect if we have issues before loading. */
public static void nothing() {

}

static {
    // should be loaded by CLib
    if (CLib.hasGNUTLS() == 1) {
        globalinit();
    }
}

I find myself literally creating a function called "nothing" to call it early if necessary, but I also want it called if it's referenced earlier or if we don't call nothing(). Now, I could do some nasty logic involving checking a boolean, but then you get into thread safety, and blah. I suppose you could, but it's not pretty. Is there a way to explicitly call GNUTLS.<clinit>();?

JavaProphet
  • 931
  • 14
  • 29
  • Just to clarify: the purpose of the `nothing` method is just to ensure that the class has been loaded, right? You need to load the class so that its static initializer runs, even though you don't need to do anything *else* with the class, yet, besides making the JVM load it. – Wyzard Aug 12 '15 at 02:01
  • http://stackoverflow.com/questions/31027000/does-jvm-load-all-the-classes-mentioned-by-the-classpath/31028160#31028160 – ZhongYu Aug 12 '15 at 02:13

1 Answers1

6

The static initializer will always run before your method, because the initializer runs when the class is initialized. JLS-8.7. Static Initializers says (in part)

A static initializer declared in a class is executed when the class is initialized (§12.4.2). Together with any field initializers for class variables (§8.3.2), static initializers may be used to initialize the class variables of the class.

And, there is no way for you explicitly invoke any initializer (static or otherwise). However, Class.forName(String) says (in part)

A call to forName("X") causes the class named X to be initialized.

Elliott Frisch
  • 198,278
  • 20
  • 158
  • 249
  • Yes, I know. That's not my question. You have to reference the class for it to be loaded, and then call the static initializer, hence `nothing()` to reference the class. – JavaProphet Aug 12 '15 at 02:00
  • 1
    You might take a look at [`Class.forName(String)`](https://docs.oracle.com/javase/7/docs/api/java/lang/Class.html#forName%28java.lang.String%29). And yes, you have to reference a class for it to be loaded. – Elliott Frisch Aug 12 '15 at 02:01
  • 1
    It's unclear, but I think the idea is to call a do-nothing method just to trigger classloading — not to somehow call the static initalizer (again) from *within* a method. – Wyzard Aug 12 '15 at 02:02
  • 3
    @JavaProphet You don't need a do-nothing method for that. Just mentioning its name is sufficient, e.g. `MyClass.class;` as a complete statement. – user207421 Aug 12 '15 at 02:05
  • 2
    loading a class does not trigger initializing the class. – ZhongYu Aug 12 '15 at 02:14
  • @ElliotFrisch The initialiser runs when #12.4.1 says so, and 'not ... under any other circumstance', not immediately after the class is loaded'. – user207421 Aug 12 '15 at 03:07
  • @EJP The Javadoc for `Class.forName(String)` clearly states that it is equivalent to `Class.forName(className, true, currentLoader)`, which according to the Javadoc, initializes the class. So it must do one or more of the things mentioned in #12.4.1 under the hood. But that's alright. – Erwin Bolwidt Aug 12 '15 at 03:59
  • I know this is an old thread, but the `Class.forName()` answer totally made my day. I needed to re-run static initialization during unit testing to make sure that it was working correctly with multiple different properties configurations, and sticking `Class.forName()` at the top of the test forced reinitialization. +1 – mcwayliffe Jun 15 '22 at 14:56