Java - How Class is loaded and initialized

http://javarevisited.blogspot.de/2012/12/how-classloader-works-in-java.html

http://javarevisited.blogspot.sg/2012/07/when-class-loading-initialization-java-example.html

Sometimes I can't open this page without proper proxy, so I have to copy the content here.


What is ClassLoader in Java

ClassLoader in Java is a class which is used to load class files at runtime in Java. Java code is compiled into class file by javac compiler and JVM executes Java program, by executing byte codes written in class file. ClassLoader is responsible for loading class files from file system, network or any other source.

There are three default class loader used in Java, Bootstrap , Extension and System or Application class loader. Every class loader has a predefined location, from where they loads class files.

Bootstrap ClassLoader is responsible for loading standard JDK class files from JRE/lib/rt.jar. it is parent of all class loaders in Java. Bootstrap class loader don't have any parents, if you call String.class.getClassLoader() it will return null and any code based on that may throw NullPointerException in Java. Bootstrap class loader is also known as Primordial ClassLoader in Java.

Extension ClassLoader delegates class loading request to its parent, Bootstrap and if unsuccessful, loads class form jre/lib/ext directory or any other directory pointed by java.ext.dirs system property. Extension ClassLoader in JVM is implemented by  sun.misc.Launcher$ExtClassLoader.

Third default class loader used by JVM to load Java classes is called System or Application class loader and it is responsible for loading application specific classes from CLASSPATH environment variable, -classpath or -cp command line option, Class-Path attribute of Manifest file inside JAR. Application class loader is a child of Extension ClassLoader and its implemented by sun.misc.Launcher$AppClassLoader class.
Remember Classpath is used to load class files while PATH is used to locate executable like javac or java command.

except Bootstrap class loader, which is implemented in native language mostly in C,  all  Java class loaders are implemented using java.lang.ClassLoader.

How ClassLoader works in Java

ClassLoader in Java works on three principle: delegation, visibility and uniqueness.

Delegation principle forward request of class loading to parent class loader and only loads the class, if parent is not able to find or load class.

Visibility principle allows child class loader to see all the classes loaded by parent ClassLoader, but parent class loader can not see classes loaded by child.

Uniqueness principle allows to load a class exactly once, which is basically achieved by delegation and ensures that child ClassLoader doesn't reload the class already loaded by parent.

How to load class explicitly in Java

Java provides API to explicitly load a class by Class.forName(classname) and Class.forName(classname, initialized, classloader). Class is loaded by calling loadClass() method of java.lang.ClassLoader class which calls findClass() method to locate bytecodes for corresponding class.

.class.getClassLoader() 可以得到 load 这个class的 ClassLoader。

Where to use ClassLoader in Java

ClassLoader in Java is a powerful concept and used at many places. One of the popular example of ClassLoader is AppletClassLoader which is used to load class by Applet, since Applets are mostly loaded from internet rather than local file system, By using separate ClassLoader you can also loads same class from multiple sources and they will be treated as different class in JVM. J2EE uses multiple class loaders to load class from different location like classes from WAR file will be loaded by Web-app ClassLoader while classes bundled in EJB-JAR is loaded by another class loader. Some web server also supports hot deploy functionality which is implemented using ClassLoader. You can also use ClassLoader to load classes from database or any other persistent store.

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 it's actually being used it can sit inside before being initialized. 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

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 either using new() keyword or using reflection using class.forName()
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.

How Class is initialized in Java

It's important to know in which order various fields (static and non static), block (static and non static), various classes (sub class and super class) and various interfaces (sub interface, implementation class and super interface) is initialized in Java.

Here are some of the rules of class initialization in Java:

1) Classes are initialized from top to bottom so field declared on top initialized before field declared in bottom
2) Super Class is initialized before Sub Class or derived class in Java
3) If Class initialization is triggered due to access of static field, only Class which has declared static field is initialized and it doesn't trigger initialization of super class or sub class even if static field is referenced by Type  of Sub Class, Sub Interface or by implementation class of interface.
4) interface initialization in Java doesn't cause super interfaces to be initialized.
5) static fields are initialized during static initialization of class while non static fields are initialized when instance of class is created. It means static fields are initialized before non static fields in Java.
6)non static fields are initialized by constructors in Java. sub class constructor implicitly call super class constructor before doing any initialization, which guarantees that non static or instance variables of super class is initialized before sub class.

Examples of  class initialization in Java:
Here is an example of when class is initialized in Java. In this example we will see which classes are initialized in Java.

/**
 * Java program to demonstrate class loading and initialization in Java.
 */
public class ClassInitializationTest {

    public static void main(String args[]) throws InterruptedException {
 
        NotUsed o = null; //this class is not used, should not be initialized
        Child t = new Child(); //initializing sub class, should trigger super class initialization
        System.out.println((Object)o == (Object)t);
    }
}

/**
 * Super class to demonstrate that Super class is loaded and initialized before Subclass.
 */
class Parent {
    static { System.out.println("static block of Super class is initialized"); }
    {System.out.println("non static blocks in super class is initialized");}
}

/**
 * Java class which is not used in this program, consequently not loaded by JVM
 */
class NotUsed {
    static { System.out.println("NotUsed Class is initialized "); }
}

/**
 * Sub class of Parent, demonstrate when exactly sub class loading and initialization occurs.
 */
class Child extends Parent {
    static { System.out.println("static block of Sub class is initialized in Java "); }
    {System.out.println("non static blocks in sub class is initialized");}
}

Output:
static block of Super class is initialized
static block of Sub class is initialized in Java
non static blocks in super class is initialized
non static blocks in sub class is initialized
false

Let's have a look on another example of class initialization in Java:

/**
 * Another Java program example to demonstrate class initialization and loading in Java.
 */

public class ClassInitializationTest {

    public static void main(String args[]) throws InterruptedException {
 
       //accessing static field of Parent through child, should only initialize Parent
       System.out.println(Child.familyName);
    }
}

class Parent {
    //compile time constant, accessing this will not trigger class initialization
    //protected static final String familyName = "Lawson";
 
    protected static String familyName = "Lawson";
 
    static { System.out.println("static block of Super class is initialized"); }
    {System.out.println("non static blocks in super class is initialized");}
}

Output:
static block of Super class is initialized
Lawson


Observation

1. Here class initialization occurs because static field is accessed which is not a compile time constant. had you declare "familyName" compile time constant using final keyword in Java (as shown in commented section) class initialization of super class would not have occurred.

2. Only super class is initialized even though static field is referenced using sub type.


你可能感兴趣的:(Java - How Class is loaded and initialized)