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.
Related
Looks like I am missing important concept on locking a class and it's related classloading event.As per my knowledge in java we can use any class only if classloader has already loaded the class ( byte code ) in memory. Based on this assumption I was thinking that "static block
of SharedQ class should execute when statement synchronized (SharedQ.class) { ... } executes in below code". But thats not the same.
Can anyone please explain what is happening here exactly.
public class VerifyClassLoadingOnClassLock {
public static void main(String[] args) {
show();
}
private static void show() {
synchronized (SharedQ.class) {
System.out.println(" Method Show() executing from Main() .... ");
}
}
}
public class SharedQ {
static {
System.out.println(" Classloader is loading SharedQ ");
}
public static void writeStream() {
// some multiThread code here
}
}
Output is : Method Show() executing from Main() ....
The class will have been loaded, but not necessarily initialized. Basically, there's a Class object available when you synchronize on it, but until something uses a member of the class, it doesn't have to be initialized.
From the JVM specification section 5.5:
Initialization of a class or interface consists of executing its class or interface initialization method (§2.9).
A class or interface may be initialized only as a result of:
The execution of any one of the Java Virtual Machine instructions new, getstatic, putstatic, or invokestatic that references the class or interface (§new, §getstatic, §putstatic, §invokestatic). All of these instructions reference a class directly or indirectly through either a field reference or a method reference.
Upon execution of a new instruction, the referenced class or interface is initialized if it has not been initialized already.
Upon execution of a getstatic, putstatic, or invokestatic instruction, the class or interface that declared the resolved field or method is initialized if it has not been initialized already.
The first invocation of a java.lang.invoke.MethodHandle instance which was the result of resolution of a method handle by the Java Virtual Machine (§5.4.3.5) and which has a kind of 2 (REF_getStatic), 4 (REF_putStatic), or 6 (REF_invokeStatic).
Invocation of certain reflective methods in the class library (§2.12), for example, in class Class or in package java.lang.reflect.
The initialization of one of its subclasses.
Its designation as the initial class at Java Virtual Machine start-up (§5.2).
Prior to initialization, a class or interface must be linked, that is, verified, prepared, and optionally resolved.
Section 5 of the specification talks a lot about all of this - in particular, it differentiates between loading, linking and verification.
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.
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)
I encountered the following case:
I have a Singleton:
public class BookManager {
private boplean initialized = false;
private static BookManager instance;
static {
instance = new BookManager();
}
public void init() {
//Performs some initialization code
initialized = true;
}
public List<Book> getAllBooks() {
if (!initialized) {
throw new Exception("Not initialized!");
}
//do some code to get the books list and return it
}
}
The singleton is initialized and the init method is called during the application initialization, and works well.
After some time (not sure why) -
The use case where the exception is thrown is at at the following code:
BookManager.getInstance().getAllBooks();
I am sure that "init" method was called when the application started,
so I suspect the BookManager class was unloaded.
And when the above call was made, the class was reloaded but no call to "init" method was made.
Can someone explain in what cases a class loader is being collected by GC ?
(why the class is begin unloaded?)
I could find no reference to unloading of classes in the JBoss class loading documentation. However if you check out chapter 12.7. Unloading of Classes and Interfaces of the JLS a class can only be unloaded once the class loader is no longer reachable. That means the application has to be undeployed first. This is something that's handled by the JVM so JBoss can't do much here.
Having that said, storing stuff in static variables is unsupported by Java EE.
What's the exception you get? NullPointerException? What you can do is attache a debugger and check the object id of BookManager.class in the #init and #getAllBooks method. If it's the same (which I assume) no unloading happened.
I'm trying to define a custom ClassLoader.
public class ExampleLoader extends ClassLoader
{
public Class<?> findClass(String name) throws ClassNotFoundException
{
System.out.println("This never gets printed");
return super.findClass(name);
}
public Class<?> loadClass(String name, boolean b)
throws ClassNotFoundException
{
System.out.println("This never gets printed");
return super.loadClass(name, b);
}
}
And of course my code to test it:
public class Tester
{
public static void main(String[] args)
{
Thread t = new FooThread();
t.setContextClassLoader(new ExampleLoader());
t.start();
}
}
class FooThread extends Thread
{
public void run()
{
new RandomClass();
}
}
The problem is that my lines never get printed. Clearly I'm missing something.
This is related to bug 4868493. Here's a cite of relevance:
Unfortunately the documentation for getContextClassLoader and
setContextClassLoader might lead one to the conclusion that the
submitter's code should work as expected.
However, there is a basic rule in class loading - no class can ever
automatically load a class which is "downstream", i.e. which cannot
be directly loaded by that class' ClassLoader or one of its ancestor
ClassLoaders.
This is described in a number of places. For example, meditate on
the white paper available here:
http://www.javageeks.com/Papers/ClassForName/index.html
to gain enlightenment.
The key point seems to be that the context class loader is not used
automatically by the Java language. It's only a conventional place to
store the context class loader so that other classes can use it with the
3-argument form of Class.forName.
The spec for Thread.getContextClassLoader and Thread.setContextClassLoader
should be clarified, and the meaning of "context class loader" should
be clarified. Re-classifying as a doc bug.
The spec has not been clarified yet.
To get it to work what you initially want, replace new RandomClass() by
Class.forName(RandomClass.class.getName(),
true,
getContextClassLoader()).newInstance();
This prints, contradictorily, the following:
This never gets printed
Normally, all classloaders in a JVM are organized in a hierarchy such that every classloader (except for the primordial classloader that bootstraps the entire JVM) has a single parent. When asked to load a class, every compliant classloader is expected to delegate loading to its parent first and attempt to define the class only if the parent fails.
Same thing is happening in your case. "RandomClass" is to be loaded, ContextClassLoader delegates to its parent an so on. And one of parent class loader was able to load "RandomClass" (RandomClass was in classpath of parent). Because of this reason your SOP doesn't show up.
Reference following article little old but good:
http://www.javaworld.com/javaworld/javaqa/2003-06/01-qa-0606-load.html?page=1