In this third part of series about Java ClassLoader we will show how class loaders interact with namespaces in Java, and how using class loaders it is possible to have two or more instances of a static field.

In the previous article we learned how to change a class’ class loader. Can we do anything interesting now, that we know how to do it? We could use it for example to divide our program into two namespaces. Every different class loader represents a different namespace. Static fields of classes inside one namespace are separate from static fields of classes from other namespaces. If we set a value of a specific static field in namespace A, objects from namespace B will not be able to read it, and vice versa.

Let’s see how it works. We will have a public static Integer field in some class, and we will be trying to access this field from classes loaded with different class loaders. Here is this field:

1:
2:
3:
4:
5:
6:
7:
8:
public class StaticHolder {
    /**
     * Static variable with default value of null. (Normally it
     * would be good to have getter and setter methods here,
     * but this time we will not declare them, in sake of simplicity.)
     */
    public static Integer value = null;
}

Below is also the class used to access the field. It will read the value of the field and then change it to 4. Default value for any class field is null, so that’s what we expect to see as the start value. In a normal, single-classloader program, after changing the value of the static field, the change would be visible to other objects reading that field. We will see what happens with multiple classloaders.

1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
public class StaticAccessor {
    /**
     * Accesses the static field from StaticHolder class.
     * It reads its value and after that sets it to 4.
     */
    @Override
    public void runMe() {
        System.out.println("--- Starting runMe. Static value: "
            + StaticHolder.value);
        StaticHolder.value = 4;
        System.out.println("--- Finishing runMe. Static value: "
            + StaticHolder.value);
    }
}

In our experimental main method we will create this time two CustomClassLoaders and load our StaticAccessor field with both of them. We will then create two instances of the StaticAccessor class, each of them from the different class loader, and run their runMe() methods.

You can find the implementation of our CustomClassLoader in the previous article.

1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
public class StaticAccessorTest {
    /**
     * This main method shows what happens when we load two
     * classes with two different ClassLoader's and access
     * some other class' static field from them.
     */
    public static void main(String... strings) throws Exception {
        // Using the first ClassLoader
        CustomClassLoader loader1 =
            new CustomClassLoader(StaticAccessorTest.class.getClassLoader());
        Class<?> clazz1 = loader1.loadClass("javablogging.StaticAccessor");
        Object instance1 = clazz1.newInstance();
        clazz1.getMethod("runMe").invoke(instance1);

        // Using the second ClassLoader
        CustomClassLoader loader2 =
            new CustomClassLoader(StaticAccessorTest.class.getClassLoader());
        Class<?> clazz2 = loader2.loadClass("javablogging.StaticAccessor");
        Object instance2 = clazz2.newInstance();
        clazz2.getMethod("runMe").invoke(instance2);
    }
}

When we run the program, we will get the following output:

loading class 'javablogging.StaticAccessor'
...
--- Starting runMe. Static value: null
loading class 'java.lang.Integer'
--- Finishing runMe. Static value: 4
loading class 'javablogging.StaticAccessor'
...
--- Starting runMe. Static value: null
loading class 'java.lang.Integer'
--- Finishing runMe. Static value: 4

When you look at the “— Starting runMe” lines, you will notice that both of them show null! Although we changed the static field to 4 in the first run of runMe(), the value read in the second runMe() shows once again null. The reason for it is that we have now two separate namespaces, as on the image below:





In normal programs it may be hard to see a usage for such tricks. Separating namespaces in such a way may be however useful for example when doing unit tests, when you want to be sure that every test runs in a completely separate sandbox, or when implementing frameworks or application servers, where every deployed application should be isolated from others.

You can read more about class loaders and namespaces in Java for example in this article: http://www.artima.com/underthehood/classloadersP.html.