7

I have a question regarding static blocks:

Let's say i've got a class looking like this:

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

and I define a variable of type SomeClass somewhere.

public static void main(String args[]) {
    SomeClass foo;
}

Now i thought the static block would have been executed but it wasn't. As far as i know the static block is executed as soon as the classloader loads the SomeClass class. Now to my real question:

Isn't the class loaded as soon as I define a variable of that type?. If yes why isn't the static block executed?

If the answer should be no, then how can i know if a class has already been loaded by the class loader and what are the different possibilities to have the class loaded (I know of 2: initializing the variable & using a static field/method)

ParkerHalo
  • 4,341
  • 9
  • 29
  • 51
  • 4
    The compiler could remove foo, the import of SomeClass in this case. `Class.forName("... SomeClass")` does initialize the class. – Joop Eggen Nov 19 '15 at 13:26
  • @JoopEggen ah ok, but couldn't the compiler also remove foo when it was initialized but never used? Or will the compiler never do that? – ParkerHalo Nov 19 '15 at 13:27
  • What if you do `SomeClass foo = new SomeClass();` – Maraboc Nov 19 '15 at 13:27
  • @Maraboc when i initialize foo with `new SomeClass()` then it will execute the static block – ParkerHalo Nov 19 '15 at 13:28
  • 2
    It is a common optimization for the compiler (and runtime) to delay loading classes until they are needed. import statements are directives to the compiler, but are not executed at run time. I have seen environments where a class is loaded only when a method that references the class is executed but not when other methods that don't reference the class are executed. – dsh Nov 19 '15 at 13:28
  • @dsh so it's also depending on the compiler that is used? – ParkerHalo Nov 19 '15 at 13:33
  • 1
    Class.forName is overloaded with a boolean parameter to initialize the _class_; per default true. Initializing the _variable_ probably suffices to invoke class loading and initialization, even if the entire object is optimized away. One should consider that (ideally) there are more than one java compilers. – Joop Eggen Nov 19 '15 at 13:42
  • @JoopEggen many thanks! I think i got it now! – ParkerHalo Nov 19 '15 at 13:44
  • 1
    @ParkerHalo Yes. A naive compiler would not remove the unused variable. – dsh Nov 19 '15 at 16:53

2 Answers2

5

Refer to this doc: http://www.javaworld.com/article/2077260/learn-java/learn-java-the-basics-of-java-class-loaders.html

So when are classes loaded? There are exactly two cases: when the new bytecode is executed (for example, FooClass f = new FooClass();) and when the bytecodes make a static reference to a class (for example, System.out).

In your example, SomeClass foo; does neither execute the bytecode of SomeClass nor make a static reference to SomeClass. That's why the class is not loaded.

So following your example, add a static field in the class

public class SomeClass {
    static {
        System.out.println("static block");
    }

    static String abc = "abc";
}

SomeClass is loaded in either:

SomeClass foo = new SomeClass();

Or

System.out.println(SomeClass.abc);
Bon
  • 3,073
  • 5
  • 21
  • 40
  • Ermm .... the `SomeClass` class is >>loaded<<, but it isn't >>initialized<<, and class initialization is when the static blocks get executed. – Stephen C Nov 19 '15 at 15:12
4

Isn't the class loaded as soon as I define a variable of that type?.

Yes, it is loaded1, but it won't be initialized as a result of declaring a variable. However, when you create an instance of that type, or access a static field of that type, that is sufficient to trigger initialization, including the execution of static blocks.

See this related Q&A - When does static class initialization happen? - which lists all of the things that can trigger initialization.


How can i know if a class has already been loaded by the class loader and what are the different possibilities to have the class loaded (I know of 2: initializing the variable & using a static field/method)

The only ways I can think of for finding out when a class is loaded (as distinct from initialized) are:

  • turning on the JVM's class loader messages (using -verbose:class), or

  • using a customer classloader that notices, and does something appropriate when it sees a request to load the class.

A class is actually going to be loaded:

  • when it is explicitly loaded using Class.forName or similar, or a direct call to a classloader,

  • when it is necessary to load it in order to link another class, or

  • at JVM launch time, if the class is named as the entry point class.

The loading / linking / initializing steps are specified in Chapter 12 of the JLS.


1 - In fact, SomeClass needs to be loaded at the same time that the class containing that main method is linked; i.e. before the method containing that local declaration is called.

Community
  • 1
  • 1
Stephen C
  • 698,415
  • 94
  • 811
  • 1,216