Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Multiple instances of static variables

I'm experimenting with using different classloaders to load a particular class, and see if the static variables in that class can have different instances.

Basically, I'm trying to write code for what Stephen C has mentioned in this answer.

Here are my classes:

CustomClassLoader.java

class CustomClassLoader extends ClassLoader
{
    public Class loadClass(String classname)  throws ClassNotFoundException {
        return super.loadClass(classname, true);
    }
}

Test.java (which contains the driver)

class Test {
        public static void main(String[] args) throws Exception {
                CustomClassLoader c1 = new CustomClassLoader();
                CustomClassLoader  c2 = new CustomClassLoader();
                Class m1, m2;

                m1 = c1.loadClass("A");
                m2 = c2.loadClass("A");

                m1.getField("b").set(null, 10);

                System.out.println(m1.getField("b").get(null));
                System.out.println(m2.getField("b").get(null));
        }

}

A.java (which contains the static variable)

class A {
        public static int b = 5;
}

When I run the Test class, I get the following output:

$ java Test
10
10

I expected the output to be 10 and 5. How can I make the code create two instances of my static variable?

Note: I'm doing this only for experimentation and learning - but I'd be interested to know if there could be any real world application of this.

like image 807
AbdullahC Avatar asked May 10 '11 12:05

AbdullahC


2 Answers

It looks as though the class "A" is being loaded by the parent class loader, rather than your CustomClassLoader (because you call super.loadClass).

The following untested amendment should allow you to define the "A" class using your own class loader (while delegating everything else to the parent loader).

Apologies for the horrible bodge where I assume the single inputStream.read() will read everything! But you can hopefully see what I mean.

    public Class loadClass(String classname)  throws ClassNotFoundException {
    if (classname.equals("A")) {
        InputStream is = getResourceAsStream("A.class");
        byte[] bodge = new byte[8192];  // Should read until EOF
        try {
            int len = is.read(bodge);
            return defineClass("A", bodge, 0, len);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    return super.loadClass(classname, true);
}

You'll probably then end up with ClasscastExceptions or something similar...

like image 82
Paul Cager Avatar answered Oct 19 '22 06:10

Paul Cager


Your problem is that new CustomClassLoader() creates a classloader that will try to delegate loading classes to the system classloader - and that will be the same for both instances. Your CustomClassLoader also isn't even able to load classes itself. Try using an URLClassLoader and passing null as parent.

As for real world applications: it's essential for Java Web containers and app servers by allowing different apps to be completely isolated from each other even though they may be using many of the same classes.

like image 36
Michael Borgwardt Avatar answered Oct 19 '22 06:10

Michael Borgwardt