Difference static behaviour between MyClass.class and Class.forName(“MyClass”) - java

I'm not sure what's the difference of loading static variables/blocks between MyClass.class and Class.forName("MyClass"), for example, I have below class:
package test;
public class SampleClass{
public static SampleClass instance = new SampleClass();
private SampleClass(){
System.out.println("SampleClass Instance Created");
}
}
Then, in another class, I accessed the class object of above SampleClass by using:
System.out.println(SampleClass.class);
Then, the output will be:
class test.SampleClass
If I changed to use class.forName(), as below:
System.out.println(Class.forName("test.SampleClass"));
Then, the output will be:
SampleClass Instance Created
class test.SampleClass
Does anybody can give me an explanation?
Thanks a lot.

The call to the Class.forName("MyClass") causes the class to be loaded at runtime. JVM also initializes that class after the class has been loaded by the classloader, so static blocks get executed.
In your case you have a static field which is the instance of your class, as this static block get executed your object is being initialized. That's why you are seeing the System.out get printed.
The .class syntax is used to get the Class of the called class. It doesn't not load the class actually.
Reference:
What does Class.forname method do?
Java Doc
Retrieving Class Object

Class.forName() uses the ClassLoader and tries to resolve class name at runtime, while .class is resolved at compile time.

class.forName() loads the class using the "caller's" class loader if the class is not already loaded.
.class doesn't load the class.

Its is just because of Class.forName() is dynamically loaded at run time your class into memory(RAM). and it will execute all static block within this class without creating reference of that class,
From offical doc:
A call to Class.forName("X") causes the class named X to be dynamically loaded (at runtime). A call to forName("X") causes the class named X to be initialized (i.e., JVM executes all its static block after class loading). Class.forName("X") returns the Class object associated with the "X" class. The returned Class object is not an instance of the "x" class itself.
Class.forName("X") loads the class if it not already loaded. The JVM
keeps track of all the classes that have been previously loaded. This
method uses the classloader of the class that invokes it. The "X" is
the fully qualified name of the desired class.
here is more information about it: http://www.xyzws.com/Javafaq/what-does-classforname-method-do/17

Thank you all above for your answers and discussions.
I thought the class will be loaded no matter using Class.forName() or MyClass.class, obviously I'm wrong. But I don't understand why it doesn't load the class when using MyClass.class.

Related

Why does .class not invoke the static block in a Class?

This is the code I have:
public class StupidClass {
static {
System.out.println("Stupid class loaded!");
}
}
And the tests I have, which I run separately.
import org.junit.Test;
public class StupidTest {
#Test
public void foo() throws ClassNotFoundException {
final Class<?> stupidClass = Class.forName("StupidClass");
System.out.println(stupidClass.getSimpleName());
}
#Test
public void bar() throws ClassNotFoundException {
final Class<StupidClass> stupidClassClass = StupidClass.class;
System.out.println(stupidClassClass.getSimpleName());
}
}
When I run test foo I will see:
Stupid class loaded!
StupidClass
But when I run the test bar all I see is:
StupidClass
Quoting from this page..
Class objects are constructed automatically by the Java Virtual
Machine as classes are loaded and by calls to the defineClass method
in the class loader.
So my understanding is, in test bar, Stupid class is loaded, otherwise I would have seen a null I guess? So Class object is created because class itself is loaded..
And now quoting from this page
Static initialization blocks are run when the JVM (class loader - to
be specific) loads StaticClass (which occurs the first time it is
referenced in code).
So I am expecting to see the "Stupid class loaded!" text in test bar as well, but I am not.
Also quoting from Thinking in Java
Each of the classes Candy, Gum, and Cookie has a static clause that is
executed as the class is loaded for the first time.
which is not very accurate it seems..
What am I missing?
Static initialization blocks are run when the JVM (class loader - to be specific) loads StaticClass (which occurs the first time it is referenced in code).
The above quote is plain wrong, but it is just one instance of a very widespread misconception.
Class is not initialized when it's being loaded, but when a static class member is first referenced. This is precisely governed by the specification.
Class loading does not occur when the class is first referenced, but at an implementation-dependent point.
The last moment when the class must be loaded is when the class is referenced, which is not the same as referencing a class member.
Class.forName initializes the class by default, but you have the choice of calling an overload that takes a boolean initialize and supplying false. You'll get the class loaded without initializing.
Class Loading and initialization are 2 different things. A class can be loaded but not initialized until it is really necessary. Static initializers are run only when a class is being initialized <> NOT loaded, "initialized"
In the first case you are loading and initializing a class when you use class.forName(), that's why the static initializers are run and hence you see "Stupid class loaded!" as output . In the second case, you are just assigning a reference of the class, the class is loaded (use java -verbose:class to see what classes are loaded) but you aren't really initializing it (or to be more precise, not doing anything that forces the initializers to run). Thus you don't see the output as Stupid class loaded!. Try doing something like calling newInstance() on the class, it should force the initialization of the class and you should see Stupid class loaded!
My code :
public class CheckPalindrome {
public static void main(String[] args) {
Class<Test> t = Test.class;
}
}
// class being loaded
class Test {
static {
System.out.println("aaa");
}
}
Classes that are loaded
...
[Loaded Test from file:/Workspaces/SampleTest/Java8/bin/]
...
^ - This shows that the class is loaded but not initialized.

How to understand "Every Class object contains a reference to the ClassLoader that defined it. "?

I know I can get a the classloader of a class by
xxxclass.class.getClassLoader(), but where exactly does the xxxclass
hold the reference of its classloader who defines it?
e.g.
public class ClassA {
System.out.println("I am class A");
}
I don't see any clue of the classloader reference in ClassA. However,
I can get the classloader of ClassA by using
ClassA.class.getClassLoader().
How does ClassA.class.getClassLoader() work?
The sentence as it appears in the documentation of ClassLoader is:
Every Class object contains a reference to the ClassLoader that defined it.
Note the two links? What they tell you is that the documentation refers to the Class object, not to the plain object of class ClassA.
Every class that you define in Java has a Class object associated with it, which allows you to look at that class in the meta level. That is, treat the class itself as an object, pass it as parameter, use reflection on it etc.
As you have noticed, one way to access the Class object is use ClassA.class. If you have a reference to an object of type ClassA:
ClassA myObj = new ClassA();
Then you can get the Class object using myObj.getClass().
So there is no reference to the ClassLoader in the myObj object, Only in its associated Class object.
Now, the other link tells you how to get the reference to the ClassLoader object once you have a Class object - through the getClassLoader() method.
Now, if you look at the source code of the Class class, you will see:
#CallerSensitive
public ClassLoader getClassLoader() {
ClassLoader cl = getClassLoader0();
if (cl == null)
return null;
SecurityManager sm = System.getSecurityManager();
if (sm != null) {
ClassLoader.checkClassLoaderPermission(cl, Reflection.getCallerClass());
}
return cl;
}
So it calls getClassLoader0() to get the class loader. Its source is:
native ClassLoader getClassLoader0();
That is, the class loader reference is actually part of the native structure of this Java class, and it is not available to see using Java language tools. Nevertheless, it exists there, and available to you through the aforesaid method.
If you write this:
public class Ball {
private Person thrower;
public Ball(Person thrower) {
this.thrower = thrower;
}
public Person getThrower() {return thrower;}
}
then every Ball object contains a reference to the Person that threw it, right?
Similarly, the Class class has something like this: (although I'm not showing how classLoader gets assigned)
public class Class {
... other stuff ...
private ClassLoader classLoader;
public ClassLoader getClassLoader() {return classLoader;}
... other stuff ...
}
and so every Class object has a reference to the ClassLoader that loaded it.
In your example, ClassA is not a Class object, so the statement doesn't apply to it. It does apply to ClassA.class which is a Class object (or refers to one at least).
In fact, it's not so simple in this case.
(Or at least, it was not so simple, until a recent update)
Java is a very high-level language, and the JVM is a rather complex beast, which is (fortunately!) hiding many details that you don't want to be concerned with when using a high-level, object-oriented language.
As already pointed out in the other answers, the Class#getClassLoader() method delegates to a private native method getClassLoader0(). Usually, you simply don't know (and should not have to care about) what a private native method does.
But thanks to the open source JDK, one can trace the path of this method call (here, for a recent version of the JDK8) :
The native getClassLoader0 method of Class is bound to JVM_GetClassLoader
The JVM_GetClassLoader method eventually calls Klass::class_loader()
The Klass::class_loader() method only returns the result of ClassLoaderData::class_loader()
The ClassLoaderData::class_loader() method finally returns the field that you are looking for
However, note that this has changed in a recent commit of the JDK9: Now, the ClassLoader is stored as a private instance field in the Class class, in order to improve performance.
If you look at the source code of java.lang.Class it appears that it delegates to a native method called getClassLoader0. So the implementation details are down to the JVM.
I'm no expert on this, but I suppose this might allow garbage collection to work by not having reference cycles in Java.

Class.forName("FQN") throws ClassNotFoundException Intermittently

I have a Java based RMI Server in which one of the interface method is like this :
public Properties process(String operation, Properties params) {
Class nodecls = Class.forName("com.example.commands." + operation);
}
This method runs fine all the time but sometimes (say once in a million RMI calls) throws ClassNotFoundException. What could be the reason for this? I am sure that the name passed is correct.
From XYZWS - What does Class forname method do?:
A call to Class.forName("X") causes the class named X to be dynamically loaded (at runtime). A call to forName("X") causes the class named X to be initialized (i.e., JVM executes all its static block after class loading). Class.forName("X") returns the Class object associated with the "X" class. The returned Class object is not an instance of the "x" class itself.
Class.forName("X") loads the class if it not already loaded. The JVM keeps track of all the classes that have been previously loaded. This method uses the classloader of the class that invokes it. The "X" is the fully qualified name of the desired class.
The tag wiki for classnotfoundexception has a simpler description:
The Java exception thrown when an application tries to load a class by name. Usually raised by one of:
the forName method in class Class [...]
when no definition for the class with the specified name could be found in the classpath.
Therefore, there can only be two causes for this:
The class named "com.example.commands." + operation is not present on the Class Path.
The ClassLoader of the Class which your method is in cannot find the "com.example.commands." + operation class. Maybe some reflection trick broke it.
However, you should never have to bother with this, as your method wouldn't even compile - it's of a non-void return type, while you never included a proper return statement.

Class & ClassLoader

I have a Custom Classloader : CustomClassLoader(extends ClassLoader)
I have a class : IntegerPrint
I load my class with my Custom ClassLoader. I was expecting SOPs in the below code to return the same value. But the first SOP prints "sun.misc.Launcher$AppClassLoader#.." & second SOP prints "CustomClassLoader#.."
Why it happens so? Please advise.
public class IntegerPrinterTest {
public static void main(String[] args) throws Exception {
CustomClassLoader loader = new CustomClassLoader(IntegerPrinterTest.class.getClassLoader());
Class<?> clazz = loader.loadClass("IntegerPrinter");
System.out.println(IntegerPrinter.class.getClassLoader());
System.out.println(clazz.getClassLoader());
}
}
What did you expect?
In
System.out.println(IntegerPrinter.class.getClassLoader());
you create a
Class<IntegerPrint>
object, and surely, its class (Class) must have been loaded by some class loader. It takes no genius to imagine that Class must have been loaded very early, even before your code even gains control.
Please run your example with
java -verbose:class ....
to see which classes are laoded in what order.
The first call:
IntegerPrinter.class.getClassLoader()
Will actually do:
IntegerPrinterTest.class.getClassLoader().loadClass("IntegerPrinter")
So it totally ignores your custom classloader.
In other words: your own classloader is not actually used for any objects you create using native calls like "new" etc. To do that it should be responsible for loading the IntegerPrinter class as well.
It is rather circumspect (and in general useless) to do it in the same class but you could do:
Class<?> clazz = loader.loadClass("IntegerPrinterTest");
clazz.getMethod("main").invoke(null);
(note this code is not tested but should approximate something that works)

When exactly is NoClassDefFoundError thrown?

How do runtime dependencies in Java work exactly. For example, is code like this possible if Impl1 or Impl2 are not in the classpath at runtime:
Thinger t;
if (classIsAvailable(Impl1.class)) t = new Impl1();
else t = new Impl2();
t.doThing();
Or if there is no common interface:
if (classIsAvailable(Impl1.class)) Impl1.doThingThisWay();
else Impl2.doThingTheOtherWay();
You can't do it exactly like this, because in order to evaluate Impl1.class, said class must be available (i.e. loaded). You can however try to load a specific class by its name
Class aClass = classLoader.forName("Impl1");
If this does not fail (throw an Exception) you can create an instance of this class using newInstance().
Of course, in order to be able to use your class, you have to make sure it implements an Interface, which is known at compile time. In this case you can cast your created object to that interface type and continue using it.
This article has some sample code.
ClassNotFoundException is thrown when
an application tries to load in a class through its string name using:
* The forName method in class Class.
* The findSystemClass method in class ClassLoader .
* The loadClass method in class ClassLoader.
but no definition for the class with the specified name could be found.
You may also find http://www.xyzws.com/javafaq/what-does-classforname-method-do/17 useful.
HTH
Your example would fail with a NoClassDefFoundError when your class is loaded with either Impl1 or Impl2 not in the classpath, so none of the code would execute in that case.

Categories

Resources