49

What is the best and cleanest way to do this? Specifically, I need some code in a static initializer block to run in that class, but I'd like to make this as clean-looking as possible.

OrangeDog
  • 36,653
  • 12
  • 122
  • 207
Artem
  • 6,420
  • 6
  • 26
  • 26
  • I've seen this type of suggestion: Class aClass = A.class; But it looks kind of ugly, and generates an un-used variable warning. – Artem Aug 24 '10 at 19:11
  • you can suppress the warning with `@SuppressWarnings("unused")` – Aaron Novstrup Aug 24 '10 at 19:15
  • 8
    referencing a class literal like this *will not* cause the class to be initialized. In older versions, it did, but as of Java 5, it doesn't. – erickson Aug 24 '10 at 19:17
  • @erickson Although if you compile with `-source 1.4 -target 1.4`, it will still initialise the class on 1.5+. – Tom Hawtin - tackline Aug 24 '10 at 19:28
  • 7
    @Tom H. Yes, but why would you do that? – Tom Aug 24 '10 at 19:30
  • @Artem This EXACTLY doesn't work. I pass the class descriptor to a method and turns out it's static block is still not called and the class is nowhere to be found. I guess it's compile constant, not a real class member. – Agent_L Sep 15 '16 at 12:48

6 Answers6

62

Loading != Initialization.

You want your class to be initialized (this is when static blocks executed, among other things).

An excerpt from the Java Language Specification says:

A class or interface type T will be initialized immediately before the first occurrence of >any one of the following:

  • T is a class and an instance of T is created.
  • T is a class and a static method declared by T is invoked.
  • A static field declared by T is assigned.
  • A static field declared by T is used and the field is not a constant variable (§4.12.4).
  • T is a top-level class, and an assert statement (§14.10) lexically nested within T is executed.

Invocation of certain reflective methods in class Class and in package java.lang.reflect also causes class or interface initialization. A class or interface will not be initialized under any other circumstance.

Doh, anovstrup, already said it: Just make an empty static function called init. Be sure to document that well... I personally can't see any use case for this in the context of well formed code though.

  • 6
    +1 for quoting the spec! – Aaron Novstrup Aug 24 '10 at 19:32
  • Thanks longpoke. Makes a lot of sense. See the comment I made above about using this to override flags. I can certainly do that in a static function, I just thought setting static variables is better done in a static block... – Artem Aug 24 '10 at 20:04
  • 1
    Nah setting variables doesn't have to be done in a static block, static initializers exist so you can use multiple statements to initialize a static variable, whereas a normal static variable declaration (ie: `static int x = 123; static int y = new Thing().getY();`) can only contain expressions. – L̲̳o̲̳̳n̲̳̳g̲̳̳p̲̳o̲̳̳k̲̳̳e̲̳̳ Aug 24 '10 at 22:18
  • 2
    what about doing this for performance reasons? e.g. force a static initialization while a splash screen is shown? – Sam May 28 '14 at 11:58
21

You can use the following code to force initialization of a class:

//... Foo.class ...          //OLD CODE
... forceInit(Foo.class) ... //NEW CODE

/**
 * Forces the initialization of the class pertaining to 
 * the specified <tt>Class</tt> object. 
 * This method does nothing if the class is already
 * initialized prior to invocation.
 *
 * @param klass the class for which to force initialization
 * @return <tt>klass</tt>

 */
public static <T> Class<T> forceInit(Class<T> klass) {
    try {
        Class.forName(klass.getName(), true, klass.getClassLoader());
    } catch (ClassNotFoundException e) {
        throw new AssertionError(e);  // Can't happen
    }
    return klass;
} 
Iulian
  • 219
  • 2
  • 2
  • 1
    Technically speaking just passing `Foo.class` as an argument loads it ;) – mid Dec 03 '16 at 14:10
  • @ssinghal: You say "this won't work!", but it does work. If the class is not yet initialised, this code will initialise it. If the class is already initialised, this code will effectively do nothing, which is what it should be doing in that case. – Simon Kissane Jan 11 '18 at 00:57
  • 3
    Midnightas, no, I just checked on Java 8: neither “.class” nor “.class.getName()” load the class. “Class.forName” does. – Danila Piatov May 15 '18 at 11:08
  • To catch errors, you should first check `if(klass.isPrimitive()) return;`, otherwise you will run into an exception if you pass primitive types. Of course, loading primitive types does not really make sense, but if you just load the class from a different method which may receive primitive types, this can be a problem, as I experienced myself – RcCookie Jul 22 '23 at 17:52
9
try
{
  Class.forName(class name as string)
}
catch(ClassNotFoundException e)
{
  whatever
}

That should do it.

@Longpoke

Maybe I am misunderstanding something then. Can you create an example where a class is loaded but the static initializer is not executed? Here is an example that does nothing but print out that it has loaded:

package test;

public class TestStatic 
{
    public static void main(String[] args) 
    {
        try 
        {
            Class.forName("test.Static");
        }
        catch (ClassNotFoundException e) 
        {
            e.printStackTrace();
        }
    }
}

With the following Static class being loaded:

package test;

public class Static 
{
    static
    {
        System.out.println("Static Initializer ran...");
    }
}

If the static initializers are not ran until the conditions you listed are met then why does this println get executed when I run my test? That is which of your listed conditions am I meeting?

BigMac66
  • 153
  • 1
  • 5
  • 5
    For one you can do use the overloaded form of Class.forName . The second argument determines if the class is to be initialized or not. Another possibility is to use Static.class to get a reference to the class, which does not provoke an initialization. – dertoni Aug 25 '10 at 13:29
  • 3
    Awesome thanks for explaining it to me! I have never used the other form of forName() and was unaware that the single argument form defaults the initialize flag to true. Still my response is valid as it will cause the static initializers to execute which is what I believe Artem was after. The form I suggested loads *AND* explicitly initializes the class. After all these years I still learn new things... – BigMac66 Aug 25 '10 at 19:56
  • Your method does work but really you should use the full form, especially in more complex cases when you do not know what ClassLoader loaded the class. This is covered in Sun's guide: http://java.sun.com/j2se/1.5.0/compatibility.html (see point 5) – Kevin Brock Dec 30 '10 at 22:56
4

Invisible dependencies between classes is not a good idea. I suggest moving the code in static initializer block to a static method and calling it directly in the dependent class. The static initializer block can be rewritten to call the newly created static method.

Abhinav Sarkar
  • 23,534
  • 11
  • 81
  • 97
  • This is for a very very special use. I would like to have a set of static flags that I can override for testing. Sort of like setting properties. Putting this initialization in a function call opens the door to all kinds of code being run there, but I would rather just limit it to static { DebugUtils.FLAG_TEST_USER = true; } – Artem Aug 24 '10 at 19:40
  • All of the code that can be run in the static method can be run in the static block, right? How is it limited? – Lou Franco Aug 24 '10 at 20:33
  • 1
    I think I was confused... Since the static block usually had variable initialization, I thought it was limited to that. So there are no limitations? – Artem Aug 24 '10 at 20:45
  • @Artem: You can do pretty much anything in a static block, the static block(s) of a class are guaranteed to be executed automatically before any code ever accesses that class. Wait now I'm confused if this is what you're asking because of your comment on my answer. – L̲̳o̲̳̳n̲̳̳g̲̳̳p̲̳o̲̳̳k̲̳̳e̲̳̳ Aug 24 '10 at 22:14
1

One solution would be to call a static method:

public class A {
   static { DebugUtils.FLAG_TEST_USER = true; }

   static void init() {}
}

Then invoke A.init() to force initialization.

However, doing this at all is a code smell. Consider replacing your static code with a standard constructor in a singleton object.

Aaron Novstrup
  • 20,967
  • 7
  • 70
  • 108
1

If you need to statically initilize something in a Class that means there must be client classes dependent on that.

If there is one client, or let's call it a natural home for the initializing block, I think it would be cleanest to initialize it there.

For the many equal clients case, it may be a good idea to verify from these classes that the static initalization in the other class was successful. Then the coupling is documented and you are sure the class is always initialized before the first client needs it.

Peter Tillemans
  • 34,983
  • 11
  • 83
  • 114