Saturday, 3 March 2018

Java Class Loader

We will see how java classes loaded into memory by JVM.
We mostly use default class loaders defined by JVM. But we can customize the class loading mechanism.

Java class loader will load the classes to JVM. it is as simple as statement. But as s java developer, we need to understand the class loader.  Somehow we might get "ClassNotFound Exception" during our development and class loader is culprit to cause this exception.

Every java developer know that,  Java programs will run on JVM and  when we compile the java program, it will convert it to binary code and save it as .class file.  And this .class file machine and platform independent. After that when we try to use class file, java class loader loads the class into memory.

We have three types of java class loaders:

1. Bootstrap Class loader :  It loads java core classes(JDK internal classes) that are part of Java Runtime environment. i.e it loads classes from java.lang.*, java.util.* and typically loads classes from rt.jar.

This class loader is native which means it may differ based on JVM.

2. Extension Class loader : It loads java classes from JDK extension folder i.e from $JAVA_HOME/jre/lib/ext. where ext folder contains jar packages which are extension of core java classes.
We can add ext folders and jar files to be loaded by this class loader using system property java.ext.dirs.

3. System Class loader : It loads the classes which are specified in java class path.

Class loaders have hierarchical relationship among them. Which means when request comes to load class, it delegates the request to it's parent class. If parent class is failed to load then, loader itself loads the class. Here Bootstrap is first level, Extension is second level and System class loader is third level.

How to get Class loader for class:

When we compile java program to binary code, compiler will insert one static final filed of type java.lang.class. Significance of this is , it contains method getClassLoader() which returns lass loader of that class. We will get null if class is loaded by class loader is of type Bootstrap class loader.

Ex:  java.lang.class classObj = Classname.Class;

How class loader will work:

When JVM requires a class,

1. Class loader first locate class file with fully qualified name using loadclass() method .

2. After that loader will check whether this class is already available in JVM or not using findLoadedClass() method to avoid duplicate class loading.

3. If the class is not loaded then it delegates request to it's parent class loader.

4. If parent class loader not able to find the class, then it will invoke findclass() method to read the class file of that name from native file system.

Because of point 4(loading class from native file system), Class loading process is platform dependent.

As class loaders are having hierarchical relationship, class loaded by child class loader has the visibility into classes loaded by it's parent class loader. Hence classes loaded by System class loader have the visibility into classes loaded by Extension and Bootstrap class loaders.


package com.sample.javase.testing;


public class JavaClassLoaderTest {

    public static void main(String[] args) {
       
        System.out.println("class loader of arrylist " + java.util.ArrayList.class.getClassLoader());
       
         java.lang.Class<JavaClassLoaderTest> class1= JavaClassLoaderTest.class;
         System.out.println("Class loader of this class " + class1.getClassLoader());

System.out.println("class loader for mysql is " + com.mysql.jdbc.Driver.class.getClassLoader());

    }

}

Output :

class loader of arrylist null
Class loader of this class sun.misc.Launcher$AppClassLoader@13eae6e
class loader for mysql is sun.misc.Launcher$AppClassLoader@13eae6e

If we see output we got class loader as null for Java.util.Arraylist which means it is loaded by Bootstrap class loader.

Since this class itself is in CLASSPATH, it loaded by System Class Loader.

And I have added mysql jar file to class path before executing the program. Hence mysql driver class also is loaded by System class loader.

Here when we try to load arraylist class, System class loader delegates request to Extension class loader and it delegates to Bootstrap class loader and it is able to find the class from JDK core classes and loaded it.

Same is followed for mysql jar and Bootstrap and extension class loaders failed to load and System class loader is loaded as i have added mysql jar file to CLASSPATH.

Rule to load class:

Class is loaded only once into JVM. Here uniqueness of class name is depend on package, class name and class loader type. So class is loaded only once per class loader. Hence same class will be loaded twice into JVM using two different class loader.

How to initialize class in java

1. Class will initialize from top to bottom. i.e first fields declared on top will initialize before the fields declared at bottom.

 2. If Super class is available, then it initialize first before sub or derived class.

3. If class in initialized during static filed access, then it initialize Class which has declared static fields and it won't initialize it's sub classes and interfaces.

4. Interfaces also does not initialize super interfaces.

5. Static fields are initialized during static initialization of class and non static fields are initialized during object creation of class. Hence Static files are initialed first, then non static fields are initialized.

6. Non static fields are initialized by constructor of class and sub class constructor will call super class constructor before initialization. Hence non static fields of super will initialize before sub class fields.


package com.sample.javase.testing;

public class ClassIntitizlizedSuperClassTest {

    public ClassIntitizlizedSuperClassTest() {
        System.out.println("super class constructor");
    }

    static {
        System.out.println("static block of super class.....");
    }

    {
        System.out.println("non static block of super class.....");
    }

}

package com.sample.javase.testing;

public class ClassIntitizlizedSubClassTest extends
        ClassIntitizlizedSuperClassTest {

    public ClassIntitizlizedSubClassTest() {
        System.out.println("sub class constructor");
    }

    static {
        System.out.println("static block of sub class.....");
    }

    {
        System.out.println("non static block of sub class.....");
    }

}

package com.sample.javase.testing;

public class ClassInitializedTest {

static{
        System.out.println("this class");
    }

    public static void main(String[] args) {
        //If we did not extend parent class in child class, below line will initialize only child class //including static blocks
        ClassIntitizlizedSubClassTest classIntitizlizedSubClassTest = new ClassIntitizlizedSubClassTest();
        System.out.println("child to parent....");
        //below won't print static blocks because static blocks are initialzed only once
        ClassIntitizlizedSuperClassTest classIntitizlizedSuperClassTest = new ClassIntitizlizedSubClassTest();
    }

}

Output :
this class
static block of super class.....
static block of sub class.....
non static block of super class.....
super class constructor
non static block of sub class.....
sub class constructor
child to parent....
non static block of super class.....
super class constructor
non static block of sub class.....
sub class constructor

For point 3:

package com.sample.javase.testing;

public class StaticInitializeSuperTest {
   
    public static String checkClassInit = "static";
   
    {System.out.println("super non static test....");};

    static {
        System.out.println("super static test....");

    }

}


package com.sample.javase.testing;

public class StaticInitializeSubClassTest extends StaticInitializeSuperTest{
   
    {
        System.out.println("sub non static initialize test...");
    };

    static {

        System.out.println("sub static initialize test...");
    }

}


package com.sample.javase.testing;

public class StaticInitializedTest {

    public static void main(String[] args) {

        System.out.println(StaticInitializeSubClassTest.checkClassInit);
    }

}

Output :

super static test....
static

No comments:

Post a Comment