Fundamentals 11 min read

Unlocking Java: How the JVM Loads and Instantiates Classes

This article explains the Java class‑loading lifecycle—including loading, linking, and initialization—covers the parent‑delegation model, demonstrates custom class loaders, and details the bytecode steps of object instantiation, while comparing ClassLoader.loadClass with Class.forName.

ITFLY8 Architecture Home
ITFLY8 Architecture Home
ITFLY8 Architecture Home
Unlocking Java: How the JVM Loads and Instantiates Classes

1. Class Loading Process

The class loading process converts a .class file into a Class object, while object instantiation (e.g., User user = new User();) creates an instance of that class.

Each .class file corresponds to a single Class object, but many instances can be created.

Load: The compiled .class file is read as a binary stream and loaded into JVM memory, forming internal data structures via the class loader. During this phase the JVM verifies the magic number, constant pool, file length, and parent class information. In short, loading copies the class data into memory.

Link: Consists of three steps—verification, preparation, and resolution.

Verification: Checks final field correctness, static usage, and type validity.

Preparation: Allocates memory for static (class) variables and sets default values. Instance variables are not allocated until the initialization phase.

Example: during preparation only static int age = 3; receives memory; public String website = "www.beijingdesigner.com"; does not.

Resolution: Converts symbolic references in the class to direct references (e.g., a method call becomes a pointer to the method’s address).

Init: Executes the class initializer <clinit>, recursively initializing parent class static blocks, but does not invoke constructors. Static variables are set before static blocks run.

int j;
Class<Integer> integerClass = int.class;
Class<Integer> integerClass1 = Integer.class;

2. Class Loading Principles: Parent‑Delegation Model

The JVM determines class file locations using a hierarchy of class loaders.

Bootstrap ClassLoader: Loads core Java classes such as Object, System, and String.

Extension (or Platform) ClassLoader: Loads JDK extension classes (pre‑JDK 9) or platform classes (post‑JDK 9).

Application ClassLoader: Loads classes from the user’s classpath.

Class loaders are composed rather than inherited; each delegates to its parent before attempting to load a class.

ClassLoader classLoader = Son.class.getClassLoader();
ClassLoader parent = classLoader.getParent();
ClassLoader parent1 = parent.getParent();
System.out.println(classLoader);
System.out.println(parent);
System.out.println(parent1);
// Output example:
// sun.misc.Launcher$AppClassLoader@18b4aac2
// sun.misc.Launcher$ExtClassLoader@5acf9800
// null

Bootstrap classpath can be inspected via:

URLClassPath bootstrapClassPath = Launcher.getBootstrapClassPath();
URL[] urls = bootstrapClassPath.getURLs();
for (URL url : urls) {
    System.out.println(url.toExternalForm());
}
// Example entries:
// file:/D:/jdk-8u151-windows-x64/JDK/jre/lib/rt.jar
// ...

Custom class loaders can be created by extending ClassLoader and overriding findClass() to define classes from custom sources.

public class UserClassLoader extends ClassLoader {
    private String classpath;
    public UserClassLoader(String classpath) {
        this.classpath = classpath;
    }
    @Override
    protected Class<?> findClass(String name) throws ClassNotFoundException {
        try {
            byte[] classData = getData(name);
            if (classData == null) {
                throw new FileNotFoundException();
            }
            return defineClass(name, classData, 0, classData.length);
        } catch (IOException e) {
            e.printStackTrace();
        }
        return super.findClass(name);
    }
    private byte[] getData(String className) throws IOException {
        InputStream in = null;
        ByteArrayOutputStream out = null;
        String path = classpath + File.separatorChar + className.replace('.', File.separatorChar) + ".class";
        try {
            in = new FileInputStream(path);
            out = new ByteArrayOutputStream();
            byte[] buffer = new byte[2048];
            int len;
            while ((len = in.read(buffer)) != -1) {
                out.write(buffer, 0, len);
            }
            return out.toByteArray();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } finally {
            if (in != null) in.close();
            if (out != null) out.close();
        }
        return null;
    }
}
// Usage example:
UserClassLoader myClassLoader = new UserClassLoader("D:\\wp");
Class<?> sonClass = myClassLoader.loadClass("com.Son");
if (sonClass != null) {
    Object obj = sonClass.newInstance();
    System.out.println(sonClass.getClassLoader().toString());
}

3. Object Instantiation

Object creation can be analyzed from bytecode and execution steps.

Bytecode: The new instruction triggers class loading if needed, allocates memory, and pushes the reference onto the stack. dup duplicates the reference for constructor invocation. invokespecial calls <init> to run the constructor.

Execution Steps:

Check if class metadata exists in Metaspace; if not, load via parent‑delegation.

Allocate heap memory for the object, including space for reference‑type fields.

Set default values (zero, null, etc.) for fields.

Initialize the object header (hash code, lock info, class pointer).

Execute the <init> method to initialize fields, run instance initializers, and invoke the constructor.

4. ClassLoader.loadClass vs. Class.forName

// Example 1
Class<Son> sonClass = Son.class;
// Example 2
Class<?> aClass = Maint.class.getClassLoader().loadClass("com.Son");
// Example 3
Class<?> bClass = Class.forName("com.Son");

Both examples 1 and 2 load the class file into the JVM and obtain a Class object, but they do not perform linking or initialization, so static blocks are not executed.

Example 3 invokes Class.forName(className, true, callerClassLoader), which loads, links, and initializes the class; static blocks run immediately (e.g., driver registration via Class.forName("com.mysql.jdbc.Driver")).

None of the three approaches invoke the class’s constructor during loading.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

JavaclassloaderObject Instantiation
ITFLY8 Architecture Home
Written by

ITFLY8 Architecture Home

ITFLY8 Architecture Home - focused on architecture knowledge sharing and exchange, covering project management and product design. Includes large-scale distributed website architecture (high performance, high availability, caching, message queues...), design patterns, architecture patterns, big data, project management (SCRUM, PMP, Prince2), product design, and more.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.