If I declare a variable static and compiled this class into a executable jar. If I start this class using batch file like this:
java MyClass
java MyClass
java MyClass
Would all 3 process share the same variable?
No. The static variable is specific to the JVM instance. More than that, in fact - it's specific to the class loader which loads the class. So if you created three separate class loaders, each responsible for loading MyClass (not just delegating to some common parent) they'd each have a separate, independent static variable in MyClass.
Static resources are per class loader and therefore, your 3 processes have obviously three different class loaders and hence, would not share the variables.
Related
I have this code
MyClassloader loader = new MyClassloader();
Class c = loader.loadClass(classToLoad);
Thread.currentThread().setContextClassLoader(loader);
MyClass myClass = (MyClass) c.newInstance();
And classloader code is
public MyClassloader) throws IOException {
super(Thread.currentThread().getContextClassLoader());
}
The class loading works fine the problem is that static variables are not isolated, so if inside the MyClass a static variable is set all other MyClass instances get the same value.
In what can a static variable be isolated?
You delegate to the same class loader. So you will see no difference.
What should yo do? Implement class loading in your class loader, don't just delegate. For instance, inherit your class loader from URLClassLoader, initialize it properly (it means, provide a valid class path to your class loader to initialize it). Then you will see, that classes loaded by you class loader are not euqal to the classes loaded by the standard class loader, and as a consequence, their static members will be different.
Often the context class loader is inherited from URLClassLoader and thus you don't have to spend much time configuring class path for it. Instead, to initialize you class loader you can just reuse the URLs of the context class loader, as follows:
public class MyIndependentClassLoader extends URLClassLoader {
public MyIndependentClassLoader(){
super(((URLClassLoader) Thread.currentThread().getContextClassLoader()).getURLs());
}
}
Now you can use your class loader and check static members.
What is the difference between this approach and the original approach?
You know that classes are also objects (of special type): they have their own member variables, name, serialVersionUID, annotationData, etc., and their own methods, newInstance(), getFields(), getMethods(), etc. When you call
Class c = loader.loadClass("com.my.package.MyClassX");
you get c, this is an object that describes the loaded class "some class name". This c not only allows to create instances, but holds also all static members.
In your code: Your class loader does not load class directly. Instead, it delegates to the context class loader. That's why if you compare two loaded classes
Class c = loader.loadClass("com.my.package.MyClassX");
Class ct = Thread.currentThread().getContextClassLoader().loadClass("com.my.package.MyClassX");
you will see, that c and ct is the same object. If you call c.equals(ct), it will give you true. And if you call c == ct, it will also give you true. It means, this is the same class instance. That's why - naturally - if you check static variables, they will be the same. If you change static variable in one class, it will also be changed in another class, and vice versa.
In my code: The essential difference is, that the class loader loads classes itself. It does not delegate it to other class loader. I suggested to extend it from URLClassLoader to simplify our implementation (otherwise you would have implement from scratch dealing with class path, directories, jars, visibility, caching, etc.). And to avoid adding each class path element step by step I suggested to use the same class path (the same list of directories, jars, etc.) as the context class loader. So our class loader will be able to find the same classes as the context class loader.
Now check the class that this class loader loads. Let's call it ci:
Class ci = new MyIndependentClassLoader().loadClass("com.my.package.MyClassX");
If you compare these classes, you will see that c.equals(ci) gives false. Means, they are different. That's why they have also independent static members. If you change static member in one class, ct, it will not change in the other, ci, and vice versa.
Could someone explain what is the difference between Class loading and instantiating a Class. When we load a class with Static variable does it also get instantiated the same time the Class get loaded? After all static code is part of the class rather than it's individual instances. It would be helpful if someone provided an example to help me understand this better.
Here is some nice explanation(with an example and observation)
When a class is loaded and initialized in JVM - Java
When Class is loaded in Java
Class loading is done by ClassLoaders in Java which can be implemented to eagerly load a class as soon as another class references it or lazy load the class until a need of class initialization occurs. If Class is loaded before its actually being used it can sit inside before being initialized. I believe this may vary from JVM to JVM. While its guaranteed by JLS that a class will be loaded when there is a need of static initialization.
When a Class is initialized in Java
When a Class is initialized in Java
After class loading, initialization of class takes place which means initializing all static members of class. A Class is initialized in Java when :
1) an Instance of class is created using either new() keyword or
using reflection using class.forName(), which may throw
ClassNotFoundException in Java.
2) an static method of Class is invoked.
3) an static field of Class
is assigned.
4) an static field of class is used which is not a
constant variable.
5) if Class is a top level class and an assert
statement lexically nested within class is executed.
Hope that helps.
Integer.toString(123);
For the above static method call to work, the Integer class must be loaded.
Integer i = new Integer(123);
And in the above code, I've created an instance (object) of the Integer class (which must also be loaded for this to work, obviously).
Some classes are not meant to be instantiated (like the Math class, for example, which only has static methods).
Class loading
Whenever the JVM determines it needs a class (to use its static variables, to create a new object, to use its static methods etc) it will load the class and static initialisation blocks will run, static variables are initialised etc. This is (at least under normal circumstances) done only once
SomeClass.someStaticMethod(); //SomeClass is loaded (if its not already)
SomeClass.someStaticVariable; //SomeClass is loaded (if its not already)
SomeClass var=new SomeClass(); //SomeClass is BOTH loaded (if its not already) AND instantiated
As a result the following runs (as an example):
static Vector3d var=new Vector3d(); //static variables are initialised
static{
//static initialisation block are run
}
Instantiating a class
On the other hand you instantiate a class when you create an instance of the class with the new keyword; instantiating a class is creating an object of the class.
SomeClass var=new SomeClass(); //SomeClass is instantiating (and loaded if its not already)
As a result the constructor runs:
public SomeClass(){
}
and
{
//initialisation block(s) also run (but these are very uncommonly used)
}
Class loader actually loads byte code into JVM , runs static initializers.When you want to use static fields within class without creating instance of it ,class must be loaded by class loader first.Default classloader in java is java.lang.ClassLoader.This class loading is done only once.
While class instantiation is creating instance of class into memory.We can instantiate class using new.Class instantiation can be done as many times.
eg: Animal a=new Animal();
More on class loading
A class is loaded when it is referenced (e.g. by Class.forName()).
You instanciate an object by creating an instance, e.g.
Object o = new Object();
You can also instanciate an object by using reflection.
static members of a class are instanciated when the class is loaded, e.g.
public class Sample {
private static int variable = 10;
}
When I now load the class (e.g. by Class.forName("Sample");) Then the variable variable is initialized with the value 10.
If you are creating a new instance of a class and it is not loaded before the class will be loade before (atomatically). So the construct Class.forName() is only needed under special circumstances (if the class is not known by compile time e.g.).
I have two Java projects: one is a library, and the other is a console application. In the library project, I have an abstract class with a few static member variables (for global access). It looks a bit like this:
public abstract class AbstractHelper
{
public static final VarType someVar = new VarType();
}
I access the static member variables from the console application in two different classes.
For some reason, 'someVar' has unique instances across the two different classes that access it. If I access 'someVar' from an instance of Class A, I get a different object than when I access 'someVar' from an instance of Class B.
However, if I move AbstractHelper from the library project into my console application project, then it has the expected behavior (single instance of static member variable(s) shared across multiple classes)
Does anyone know why this happens?
This can happen by using different classloaders. OSGI, java-ee servers and several other technologies allow easy injection of different classloaders to the JVM.
You can resolve the problem: define both your library and your console application classes on the same classpath.
This question already has answers here:
Difference between Loading a class using ClassLoader and Class.forName
(9 answers)
Closed 5 years ago.
When dynamically loading a class, when is it appropriate to use
Class.forName("SomeClass");
and when should I use
ClassLoader.getSystemClassLoader().loadClass("SomeClass");
Or, are they two ways of doing the same thing?
They are quite different!
As stated in the documentation for Class.forName(String),
Returns the Class object associated with the class or interface with the given string name. Invoking this method is equivalent to: Class.forName(className, true, currentLoader)
(true here refers to do you want to initialize the class?)
On the other hand, ClassLoader.loadClass(String):
Invoking this method is equivalent to invoking loadClass(name, false).
(here, the boolean has nothing to do with initialization; but if you check loadClass(String, boolean) documentation, you will see that all it does is load the class, not initialize it).
The first one (Class.forName("SomeClass");) will:
use the class loader that loaded the class which calls this code
initialize the class (that is, all static initializers will be run)
The other (ClassLoader.getSystemClassLoader().loadClass("SomeClass");) will:
use the "system" class loader (which is overridable)
not initialize the class (say, if you use it to load a JDBC driver, it won't get registered, and you won't be able to use JDBC!)
Suppose you are coding a web application that will be executed on a container such as Tomcat. What Tomcat does is create a class loader for each web application (so that it can unload the webapps later and release memory -- you need a dedicated class loader for this to work!). In this situation, you can see that both calls will yield quite different results!
For more detailed (and authoritative) information on class loading and initialization, check sections 12.2 and 12.4 of the latest (3rd) edition of the Java Language Specification.
Class.forName() uses the caller's classloader and initializes the class (runs static intitializers, etc.)
loadClass is a ClassLoader method, so it uses an explicitly-provided loader, and initializes the class lazily (on first use).
Note that there's a Class.forName() that also takes a ClassLoader.
Class.forName() load and initialize the class. In class loader subsystem it executes all the three phases i.e. load, link, and initialize phases.
ClassLoader.loadClass() behavior, which delays initialization until the class is used for the first time. In class loader subsystem it executes only two phases i.e. load and link phases.
For example:
class MyClass {
static {
System.out.println("static block in MyClass");
}
}
public class TestCase1 {
public static void main(String... args) throws Throwable {
Class.forName("A");
}
} //The above TestCase1 produce output: static block in MyClass
public class TestCase2 {
public static void main(String... args) throws Throwable {
ClassLoader.getSystemClassLoader().loadClass("MyClass");
}
} //The above TestCase2 not produce any output
They are basically doing the same thing. The ClassLoader used may be different though. Class.forName uses the ClassLoader you get from this.getClass().getClassLoader() whereas your other code specifies to use the system class loader.
In most applications this will be the same class loader but in more complicated environments such as a J2EE app or an applet this may not be the case.
ClassLoader is an abstract class, however your application is always loaded by a classloader, there could be custom class loaders such as network classloader or any other source.
On the other hand Class in itself represents classes and interfaces and the class Class has a forName function that uses the current class loader in which your application is running by default to load the class.
Here is the source for the Class.forName which in turn invokes the calling classloader.
public static Class<?> forName(String className)
throws ClassNotFoundException {
return forName0(className, true, ClassLoader.getCallerClassLoader());
}
http://docs.oracle.com/javase/1.4.2/docs/api/java/lang/ClassLoader.html
http://docs.oracle.com/javase/1.5.0/docs/api/java/lang/Class.html#forName(java.lang.String)
Hint: Primordial class loader
http://docs.oracle.com/javase/1.4.2/docs/guide/security/spec/security-spec.doc5.html
I love Class loading in java...
It really depends on what context the application is being run in. You will get different results if you are using it from a web context as opposed to just a command line program.
I've also run into problems depending on what your ClassPath looks like and what I was expecting to happen.
This JavaWorld article explains a good deal about it.
Are Java static variables shared across instances of the same web application?
class MyClass
{
private static SomeClass myStaticObject = new SomeClass();
}
If a web application uses MyClass and multiple instances of that application is run on a web server, is myStaticObject initialized multiple times?
Typically, yes. Most containers will provide separate classloaders for each web application. This will result in the class being loaded multiple times when used by several applications, and thus resulting in multiple instances of the static variable.
Stating the Java Language Specification for reference:
At run time, several reference types
with the same binary name may be
loaded simultaneously by different
class loaders. These types may or may
not represent the same type
declaration. Even if two such types do
represent the same type declaration,
they are considered distinct.
By inference, multiple instances of static variables will exist, unless the classes are loaded only once by a parent class loader, and never loaded elsewhere by any other class loader.
I don't quite see the point of having a private static variable in MyClass. If it's private you cannot access it as a class variable from outside the class you defined it in. If you just want other classes to access this variable via a getter method you should remove the static keyword.