What is Class Loading?
Loading is the process of finding the binary representation of a class or interface type with a particular name and creating a class or interface from that binary representation.

When Class is Loaded?

  1. Class loading done by Class Loaders may eagerly load a class or does lazy load
  2. Eager loading happens as soon as another class references it and lazy load happens when a need of class initialization occurs.
  3. If a Class is loaded before it’s actually being used, it can sit inside before being initialized which may vary from JVM to JVM.
  4. However, it’s guaranteed by JLS that a class will be loaded when there is a need of static initialization.

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 initialization blocks will run, static variables are initialized 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

Class loader actually loads byte code into JVM , runs static initializers when you want to use static fields within class without creating an instance of it, class must be loaded by class loader first.Default classloader in java is java.lang.ClassLoader

Class Loading is mostly unpredictable

When Class is Initialized?
Class Initialization happens after class loading. 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

Which classes are Eagerly Loaded and Lazily Loaded

Eagerly Loaded Classes
are those the JVM must be able to load JVM class files. The JVM class loader loads referenced JVM classes that have not already been linked to the runtime system. Classes are loaded implicitly because: The initial class file – the class file containing the public static void main(String args[]) method – must be loaded at startup. Depending on the class policy adopted by the JVM, classes referenced by this initial class can be loaded in either a lazy or eager manner.

An eager class loader loads all the classes comprising the application code at startup. Lazy class loaders wait until the first active use of a class before loading and linking its class file.

The first active use of a class occurs when one of the following occurs: • An instance of that class is created • An instance of one of its subclasses is initialized • One of its static fields is initialized. Certain classes, such as ClassNotFoundException, are loaded implicitly by the JVM to support execution. You may also load classes explicitly using the java.lang.Class.forName() method in the Java API, or through the creation of a user class loader.

Based on the above rules, lazy class loading can be forced on the system.

Use java -XX:+TraceClassLoading to trace the loading of classes.

Use java -XX:+PrintCompilation to trace when methods are JITed.

Below is a code example of CustomClass Loader which Servers use internally for HotCode Swap without restarting the server.When you change the Quote in ServerImpl.java file the file should be reloaded by selecting the RELOAD option while running Client.java

IServer.java

public interface IServer {
	public String getQuote();
}

ServerImpl.java

public class ServerImpl implements IServer{
	@Override
    public String getQuote() {
        return "Its Working Man";
    }
}

Client.java

import java.io.IOException;
import java.net.URL;
import java.net.URLClassLoader;
import java.io.BufferedReader;
import java.io.InputStreamReader;

public class Client {
    static ClassLoader cl;
    static IServer server;

    public static void reloadServer() throws Exception {
        URL[] urls = new URL[]{new URL("file:///D:/java/HotDeplyment/appclasses")};
        System.out.println("Reloaded.....");
        cl = new URLClassLoader(urls);
        server  = (IServer) cl.loadClass("com.mugil.org.ServerImpl").newInstance();
    }

    public static void main(String [] args) throws Exception {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        reloadServer();
        while (true) {
            System.out.print("Enter QUOTE, RELOAD, or QUIT: ");
            String cmdRead = br.readLine();
            String cmd = cmdRead.toUpperCase();
            if (cmd.equals("QUIT")) {
                return;
            } else if (cmd.equals("QUOTE")) {
                System.out.println( server.getQuote());
            } else if (cmd.equals("RELOAD")) {
            	reloadServer();
            }
        }
    }
}

The Above code is not working as windows is not clearing cached .class files or JAR files. So the alternative is to try with the below Custom Class Loader(MyURLClassLoader) which in turn extends URLClassLoader again.

MyURLClassLoader.java

import java.lang.reflect.Field;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.Collection;
import java.util.jar.JarFile;

public class MyURLClassLoader extends URLClassLoader {

	public MyURLClassLoader(URL[] urls, ClassLoader parent) {
	    super(urls, parent);
	}

    /**
     * Closes all open jar files
     */
    public void close() {
        try {
            Class clazz = java.net.URLClassLoader.class;
            Field ucp = clazz.getDeclaredField("ucp");
            ucp.setAccessible(true);
            Object sunMiscURLClassPath = ucp.get(this);
            Field loaders = sunMiscURLClassPath.getClass().getDeclaredField("loaders");
            loaders.setAccessible(true);
            Object collection = loaders.get(sunMiscURLClassPath);
            for (Object sunMiscURLClassPathJarLoader : ((Collection) collection).toArray()) {
                try {
                    Field loader = sunMiscURLClassPathJarLoader.getClass().getDeclaredField("jar");
                    loader.setAccessible(true);
                    Object jarFile = loader.get(sunMiscURLClassPathJarLoader);
                    ((JarFile) jarFile).close();
                } catch (Throwable t) {
                    // if we got this far, this is probably not a JAR loader so skip it
                }
            }
        } catch (Throwable t) {
            // probably not a SUN VM
        }
        return;
    }
}

In the below code the CustomClass Loader is called to load the classes which inturn calls the Super Class loader which is again Loaders from URL Class Loader.Once it is done we have defined a custom close method which closes the JAR files or .class files which is loaded by class loader.

TestClassLoader.java

package com.mugil.org;

import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
import java.lang.reflect.InvocationTargetException;
import java.net.MalformedURLException;
import java.net.URL;

public class TestClassLoader {
	static ClassLoader cl;
    static IServer server;
	
	public static void main(String[] args) throws Exception {
		
		while(true) {
			try {
			BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
			TestClassLoader obj = new TestClassLoader();
			obj.loadAndInstantiate();			
			System.out.println(server.getQuote());			
			}
			catch (Exception e){
				
			}
			finally {
				try {
                    Thread.sleep(3000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
			}
		}    
	}
	
	void loadAndInstantiate() throws Exception {
	    MyURLClassLoader cl = null;
	    try {	    	
	        File file = new File("D:\\java\\HotDeplyment\\bin\\Sample.jar");
	        String classToLoad = "com.mugil.org.ServerImpl";
	        URL jarUrl = new URL("file:" + file.getAbsolutePath());
	        cl = new MyURLClassLoader(new URL[] {jarUrl}, getClass().getClassLoader());
	        Class loadedClass = cl.loadClass(classToLoad);
	        Object o = loadedClass.getConstructor().newInstance();
	        server  = (IServer) o;
	        
	    } finally {
	        if(cl != null)
	            cl.close();
	    } 
	}
}

Since the infinite while loop is called indefinitely with the thread sleep interval of every 3 seconds we replace the JAR file in the middle which takes the class from the new JAR file loaded.You need to change the ServerImpl.java file and build the JDK before you want to see the changes

Output

.
.
Its Working Man
Its Working Man
Its Working Man
Its Working Man
Its Working 
Its Working 
Its Working 
.
.

The Above code is not working either

Why Tomcat Server does not needs restart if changes are done in servlet and JSP?
Tomcat is capable of adding/modifying classpath to Web Application classloader at runtime. Tomcat will be having their custom Classloader implementation which allows them to add the classpaths at runtime.a new classloader is created for the Servlet/JSP with Application classloader as parent classloader. And the new classloader will load the modified class again.

It is always best to reload the entire application incase changes are done to servlet. If you were simply to reload one class, in isolation, you might break dependencies or miss some initialization steps. Therefore, it’s much safer to reload the entire application clicking deploy option in tomcat server.JSPs on the other hand, when properly coded, shouldn’t have anything in them by markup text. So reloading a single JSP, without reloading the entire app, should be safe. By default, tomcat is started in development mode, which means JSP-derived servlets recompiled when a change is detected.

In the web.xml you need to set the below config

<servlet>
   .
   .
    <!-- Add the following init-param -->
    <init-param>
        <param-name>development</param-name>
        <param-value>true</param-value>
    </init-param>
   .
   .
   .
</servlet>

In the Server.xml reloadable should be set to true

<Context path="/simple" docBase="webapps/simple"  debug="0" reloadable="true" ></Context>

More on how CustomClass loader works for Hot Deployment here

Java Bean Class – EmployeeBean

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

public class EmployeeBean {
	private String Name;
	private int EmpNo;
	private int Age;
	private float Weight;
	
	public String getName() {
		return Name;
	}
	public void setName(String name) {
		Name = name;
	}
	public int getEmpNo() {
		return EmpNo;
	}
	public void setEmpNo(int empNo) {
		EmpNo = empNo;
	}
	public int getAge() {
		return Age;
	}
	public void setAge(int age) {
		Age = age;
	}
	public float getWeight() {
		return Weight;
	}
	public void setWeight(float weight) {
		Weight = weight;
	}
	
	
	
	public EmployeeStringBean getStringBean() {
		
		EmployeeStringBean objEmpBean = new EmployeeStringBean();
		
		objEmpBean.setName(getName() == null?null:getName().toString());
		objEmpBean.setEmpNo(Integer.toString(getEmpNo()));
		objEmpBean.setAge(Integer.toString(getAge()));		
		objEmpBean.setWeight(getWeight()+"");
		
		return objEmpBean;
	}
	
	
	public static List getStringBeanList(List beanList) {
		 List stringBeanList = new ArrayList();

	        if (beanList != null) {
	            Iterator itr = beanList.iterator();

	            while (itr.hasNext()) {
	            	EmployeeBean bean = (EmployeeBean) itr.next();
	                stringBeanList.add(bean.getStringBean());
	            }
	        }

	        return stringBeanList;
	}
}

String Bean Class – EmployeeStringBean

public class EmployeeStringBean {
	private String Name;
	private String EmpNo;
	private String Age;
	private String Weight;
	
	public String getName() {
		return Name;
	}
	public void setName(String name) {
		Name = name;
	}
	public String getEmpNo() {
		return EmpNo;
	}
	public void setEmpNo(String empNo) {
		EmpNo = empNo;
	}
	public String getAge() {
		return Age;
	}
	public void setAge(String age) {
		Age = age;
	}
	public String getWeight() {
		return Weight;
	}
	public void setWeight(String weight) {
		Weight = weight;
	}	
	
	public EmployeeBean getBean()
	{
		EmployeeBean objEmployeeBean = new EmployeeBean();
		
		objEmployeeBean.setName(getName());
		objEmployeeBean.setEmpNo(Integer.parseInt(getEmpNo()));
		objEmployeeBean.setAge(Integer.parseInt(getAge()));
		objEmployeeBean.setWeight(Float.parseFloat((getWeight())));
		
		return objEmployeeBean;
	}	
}

The below code generates no compilation error in eclipse but throws error during Runtime.

public class Animal
{
  public void eat(){}
}
public class Dog extends Animal
{
  public void eat(){}
  public void main(String[] args)
  {
    Animal animal=new Animal();
    Dog dog=(Dog) animal;
  }
}

Output

Exception in thread "main" java.lang.ClassCastException: com.mugil.wild.Animal cannot be cast to com.mugil.wild.Dog
	at com.mugil.wild.Dog.main(Dog.java:12)

By using a cast you’re essentially telling the compiler “trust me. I’m a professional, I know what I’m doing and I know that although you can’t guarantee it, I’m telling you that this animal variable is definitely going to be a dog

Because you’re essentially just stopping the compiler from complaining, every time you cast it’s important to check that you won’t cause a ClassCastException by using instanceof in an if statement.

Generally, downcasting is not a good idea. You should avoid it. If you use it, you better include a check:

Animal animal = new Dog();

if (animal instanceof Dog)
{
Dog dog = (Dog) animal;
}

public class ClassA 
{	
	public void MethodA()
	{
		System.out.println("This is Method A");
	}
}

public class ClassB extends ClassA
{	
	public void MethodB()
	{
		System.out.println("I am Method in Class B");
	}
}


public class ClassC 
{
	public static void main(String[] args) 
	{
		ClassA objClassA1 = new ClassA();
		ClassB objClassB2 = new ClassB();
		
		//Child Class of Parent Type can be Created  
		ClassA objClassB1 = new ClassB();
		
		//Assigning a Parent class Type to Child Class is Not Allowed  
		//Casting Should be Carried out
		ClassB objClassA2 = (ClassB) new ClassA();
		
		objClassA1.MethodA();
		objClassB2.MethodA();
		objClassB2.MethodB();
		
		objClassB1.MethodA();
	}
}

Sample1.java

package com.apryll.package1;
//import static com.apryll.package2.sample2.Funct3;

public class Sample1 
{
	public static void main(String[] args) 
	{
		Sample1 objSample1 = new Sample1();		
		//sample2 objSample2 = new sample2();
		
		System.out.println(com.apryll.package2.sample2.City);
		
		objSample1.Funct2();
		//objSample2.Funct4();
		
		//Sample1.Funct1();
	}
	
	static void Funct1()
	{
	  System.out.println("I am Static Function 1");
	}
	
	void Funct2()
	{	
	  System.out.println(Funct3());
	  System.out.println(City);
	}		
}

Sample2.java

 package com.apryll.package2;

  public class sample2 
  {
     public static int City = 555;
     public static String Funct3()  
     {
	return "Hi there";
     }
	
     public void Funct4()  
     {
	System.out.println("Hello There");
     }
}

1

  package com.apryll.package1;
  
  import  com.apryll.package2.sample2.*;

  public class Sample1 
  {
    public static void main(String[] args) 
    {
      sample2 objSample2 = new sample2();	
    }
  }  

The Above Code Does not Work when creating a object for sample2 since in the import statements is sample2.* is given.It should be

import  com.apryll.package2.sample2;
.
.
.
.

2
While Importing class methods and variables the static will not get imported unless you specify static
import in the import statement

You can Import the Static Methods and Variables in class as below

To Import static methods and Variables

  import  static com.apryll.package2.sample2.*;  

To Import static methods and Variables

  import  static com.apryll.package2.sample2.*;  

To Import static Variable City

  import  static com.apryll.package2.sample2.City;  

To Import static Function getCityName

  import  static com.apryll.package2.sample2.getCityName;  

3
You can directly access static method and Variable declared in some other package in static void main() method as follows

  System.out.println(com.apryll.package2.sample2.City);
  System.out.println(com.apryll.package2.sample2.Funct3());

How Static and Constructor will work when class is Extended

  public class Main2 extends A   
  {
   public static void main(String args[])
    {	
	   
    }
  }

  class A extends B 
  {
    A()
    {
      System.out.println("I am A Constrctor");
    }
	
    static
   {
      System.out.println("I am Static Method");
   }
	
   {
      System.out.println("Empty");
   }
 }

 class B
 {
   B()
   {
     System.out.println("I am B Constrctor");
   }
 }

OP:I am Static Method

How Static and Constructor will work when class object is Created

   public class Main2 extends A   
  {
   public static void main(String args[])
    {	
       A objA = new A();  
    }
  }

  class A extends B 
  {
    A()
    {
      System.out.println("I am A Constrctor");
    }
	
    static
   {
      System.out.println("I am Static Method");
   }
	
   {
      System.out.println("Empty");
   }
 }

 class B
 {
   B()
   {
     System.out.println("I am B Constrctor");
   }
 }

OP:I am Static Method
I am B Constrctor
Empty
I am A Constrctor