cyberangles blog

Class.forName() Throws ClassNotFoundException: Java Class Loading Explained with Thinking in Java Example

If you’ve spent any time working with Java, you’ve likely encountered the dreaded ClassNotFoundException. One common scenario where this exception rears its head is when using the Class.forName() method. While Class.forName() is a powerful tool for dynamic class loading, its behavior is tightly linked to Java’s class loading mechanism—something many developers overlook until an exception strikes.

In this blog, we’ll demystify Class.forName(), explore why it throws ClassNotFoundException, and dive deep into Java’s class loading process. We’ll ground our discussion in a practical example inspired by Bruce Eckel’s Thinking in Java, a classic resource for understanding Java internals. By the end, you’ll not only know how to fix this exception but also grasp the "why" behind class loading in Java.

2026-02

Table of Contents#

  1. Understanding Class.forName()
  2. What is ClassNotFoundException?
  3. Java Class Loading Mechanism: The Foundation
    • 3.1 The Delegation Model
    • 3.2 Stages of Class Loading
  4. Thinking in Java Example: A Practical Demonstration
    • 4.1 Step 1: Define a Sample Class
    • 4.2 Step 2: Use Class.forName() to Load the Class
    • 4.3 Step 3: Trigger ClassNotFoundException
    • 4.4 Step 4: Resolve the Exception
  5. Common Causes of ClassNotFoundException with Class.forName()
  6. Resolving ClassNotFoundException: Step-by-Step Solutions
  7. Best Practices to Avoid ClassNotFoundException
  8. Conclusion
  9. References

1. Understanding Class.forName()#

At its core, Class.forName() is a method in Java’s java.lang.Class class that dynamically loads a class into the JVM (Java Virtual Machine) and returns a Class object representing that class. Unlike compile-time class loading (where classes are loaded automatically when referenced), Class.forName() enables runtime class loading—making it invaluable for frameworks like JDBC (where driver classes are loaded dynamically) and dependency injection containers.

Method Signature#

The most commonly used overload of Class.forName() is:

public static Class<?> forName(String className) throws ClassNotFoundException
  • Parameters: className: The fully qualified name of the class to load (e.g., com.example.MyClass).
  • Returns: A Class object representing the loaded class.
  • Throws: ClassNotFoundException if the class cannot be found.

Key Behavior#

Class.forName(className) does two critical things:

  1. Loads the class into the JVM using the current class loader (the class loader of the class calling forName()).
  2. Initializes the class (triggers static block execution and static variable initialization), unless specified otherwise (via an overloaded method with an initialize flag).

Contrast with ClassLoader.loadClass()#

Java’s ClassLoader class also has a loadClass() method for loading classes. The key difference is that loadClass() does not initialize the class by default, whereas Class.forName() does. For example:

// Loads but does NOT initialize the class
Class<?> clazz1 = ClassLoader.getSystemClassLoader().loadClass("com.example.MyClass");
 
// Loads AND initializes the class (static block runs)
Class<?> clazz2 = Class.forName("com.example.MyClass");

This distinction is critical: if a class’s initialization fails (e.g., due to a missing dependency in a static block), Class.forName() will throw an exception, while loadClass() will not (until the class is explicitly initialized later).

2. What is ClassNotFoundException?#

ClassNotFoundException is a checked exception (extends ReflectiveOperationException, which in turn extends Exception) thrown when the JVM cannot find the class specified by className during runtime.

When Does It Occur?#

  • The class is not present in the runtime classpath.
  • The fully qualified class name is misspelled (e.g., com.exmaple.MyClass instead of com.example.MyClass).
  • The class is present but not accessible to the class loader (due to security managers or class loader delegation rules).

Exception Hierarchy#

Throwable  
└── Exception  
    └── ReflectiveOperationException  
        └── ClassNotFoundException  

Since it’s a checked exception, Java requires you to handle it with try-catch or declare it in the method signature with throws.

3. Java Class Loading Mechanism: The Foundation#

To truly understand why Class.forName() throws ClassNotFoundException, we must first unpack Java’s class loading mechanism. Class loading is the process by which the JVM loads class files into memory, verifies them, and makes them available for execution.

3.1 The Delegation Model#

Java uses a parent-delegation model for class loading. When a class loader is asked to load a class, it first delegates the request to its parent class loader. Only if the parent cannot find the class does the child attempt to load it. This ensures:

  • Class uniqueness (a class is loaded once).
  • Security (core Java classes like java.lang.String are loaded by the bootstrap class loader and cannot be overridden by user-defined classes).

Three Core Class Loaders#

  1. Bootstrap Class Loader:

    • The root of the class loader hierarchy.
    • Loads core Java classes from rt.jar (e.g., java.lang, java.util).
    • Implemented in native code (not a Java class).
  2. Extension Class Loader:

    • Loads classes from the Java Extension directory (jre/lib/ext or specified via java.ext.dirs).
    • Parent: Bootstrap Class Loader.
  3. Application (System) Class Loader:

    • Loads classes from the application’s classpath (specified via -cp, CLASSPATH environment variable, or build tools like Maven/Gradle).
    • Parent: Extension Class Loader.
    • Default class loader for user-defined classes.

3.2 Stages of Class Loading#

Class loading occurs in three phases:

  1. Loading:

    • The class loader reads the .class file (from disk, network, etc.) into a Class object in memory.
    • The fully qualified class name is used to identify the class uniquely.
  2. Linking:

    • Verification: Ensures the .class file is valid (e.g., follows Java bytecode Specification, no security violations).
    • Preparation: Allocates memory for static variables and initializes them to default values (e.g., 0 for int, null for objects).
    • Resolution: Converts symbolic references (e.g., class names, method names) in the bytecode to direct references (memory addresses).
  3. Initialization:

    • Executes the class’s static block and initializes static variables to their declared values.
    • Triggered by:
      • Class.forName() (unless initialize = false).
      • First use of a new instance, static method, or static field (excluding constants).

4. Thinking in Java Example: A Practical Demonstration#

To tie these concepts together, let’s walk through a practical example inspired by Bruce Eckel’s Thinking in Java (4th Edition), which explores dynamic class loading. We’ll create a scenario where Class.forName() throws ClassNotFoundException and resolve it step by step.

4.1 Step 1: Define a Sample Class#

First, create a simple class com.example.DataProcessor with a static block to demonstrate initialization:

// File: DataProcessor.java
package com.example;
 
public class DataProcessor {
    static {
        System.out.println("DataProcessor static block initialized!");
    }
 
    public void process() {
        System.out.println("Processing data...");
    }
}

4.2 Step 2: Use Class.forName() to Load the Class#

Next, create a Main class that uses Class.forName() to dynamically load DataProcessor:

// File: Main.java
import java.lang.ClassNotFoundException;
 
public class Main {
    public static void main(String[] args) {
        try {
            // Attempt to load DataProcessor
            Class<?> processorClass = Class.forName("com.example.DataProcessor");
            System.out.println("Loaded class: " + processorClass.getName());
 
            // Create an instance (triggers constructor, not static block)
            Object processor = processorClass.getDeclaredConstructor().newInstance();
            System.out.println("Instance created: " + processor);
        } catch (ClassNotFoundException e) {
            System.err.println("Class not found: " + e.getMessage());
            e.printStackTrace();
        } catch (Exception e) { // Catch other reflection exceptions
            e.printStackTrace();
        }
    }
}

4.3 Step 3: Trigger ClassNotFoundException#

Now, let’s intentionally break things to see the exception. Suppose we misspell the class name in Class.forName():

// Mistyped class name: "com.exmaple.DataProcessor" (missing 'a' in "example")
Class<?> processorClass = Class.forName("com.exmaple.DataProcessor");

Output:

Class not found: com.exmaple.DataProcessor
java.lang.ClassNotFoundException: com.exmaple.DataProcessor
    at java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:641)
    at java.base/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(ClassLoaders.java:188)
    at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:520)
    at java.base/java.lang.Class.forName0(Native Method)
    at java.base/java.lang.Class.forName(Class.java:375)
    at Main.main(Main.java:7)

The stack trace shows the application class loader (AppClassLoader) attempted to load the class but failed, propagating ClassNotFoundException.

4.4 Step 4: Resolve the Exception#

To fix this:

  1. Correct the class name to com.example.DataProcessor.
  2. Ensure the class is in the runtime classpath.

Assuming we compile the classes into a bin directory:

# Compile DataProcessor.java
javac -d bin com/example/DataProcessor.java
 
# Compile Main.java
javac -d bin Main.java
 
# Run Main with the correct classpath
java -cp bin Main

Output:

DataProcessor static block initialized!  // From Class.forName() initialization
Loaded class: com.example.DataProcessor
Instance created: com.example.DataProcessor@2f4d3709

Success! The class is loaded, initialized (static block runs), and an instance is created.

5. Common Causes of ClassNotFoundException When Using Class.forName()#

Now that we’ve seen the example, let’s formalize the most frequent causes of ClassNotFoundException with Class.forName():

1. Incorrect Fully Qualified Class Name#

A typo in the package or class name (e.g., com.example.MyClasss instead of com.example.MyClass).

2. Class Not in Runtime Classpath#

The class exists at compile time but is missing at runtime. For example:

  • A dependency JAR is not included in the deployment package.
  • The classpath is misconfigured (e.g., using -cp incorrectly or missing entries in pom.xml for Maven/Gradle).

3. Using the Wrong Class Loader#

If Class.forName() uses a class loader that cannot access the class (e.g., a custom class loader with restricted access), the parent delegation model may fail to find the class.

4. Class Present but Not Accessible#

Security managers or module system restrictions (Java 9+) may block access to the class, even if it exists in the classpath.

6. Resolving ClassNotFoundException: Step-by-Step Solutions#

Let’s tackle each cause with actionable fixes:

1. Verify the Fully Qualified Class Name#

  • Double-check the package and class name (case-sensitive in most filesystems).
  • Use an IDE (IntelliJ, Eclipse) to auto-complete the class name to avoid typos.

2. Ensure the Class is in the Runtime Classpath#

  • Command Line: Use -cp or -classpath to specify the classpath:
    java -cp "bin:lib/*" com.example.Main  # Linux/macOS
    java -cp "bin;lib/*" com.example.Main  # Windows
  • Maven/Gradle: Ensure dependencies are declared in pom.xml (Maven) or build.gradle (Gradle) and marked as compile or runtime scope.
  • IDE: Check project settings to ensure the class is in a source directory marked for compilation (e.g., src/main/java in Maven).

3. Fix Class Loader Issues#

  • Use the system class loader explicitly if needed:
    Class<?> clazz = Class.forName("com.example.MyClass", true, ClassLoader.getSystemClassLoader());
  • Avoid custom class loaders unless necessary; if used, ensure they delegate to the parent correctly.

4. Debug with Verbose Class Loading#

Enable verbose class loading to see which classes are being loaded and by which class loader:

java -verbose:class -cp bin Main

This logs details like:

[Loaded com.example.DataProcessor from file:/path/to/bin/]

7. Best Practices to Avoid ClassNotFoundException#

  1. Use Fully Qualified Names Consistently: Avoid abbreviations or relative names.
  2. Leverage Compile-Time Checks: Prefer new MyClass() over dynamic loading when possible (compile-time validation catches missing classes early).
  3. Manage Dependencies Carefully: Use build tools (Maven/Gradle) to track dependencies and ensure they’re included at runtime.
  4. Handle Exceptions Gracefully: Log detailed error messages (class name, classpath) in catch blocks to simplify debugging.
  5. Understand Class Loader Delegation: Know which class loader is loading your classes (critical in modular apps or containers like Tomcat).

8. Conclusion#

ClassNotFoundException when using Class.forName() is often a symptom of misunderstanding Java’s class loading mechanism or runtime classpath issues. By mastering the delegation model, class loading stages, and common pitfalls, you can diagnose and resolve this exception efficiently.

The key takeaways are:

  • Class.forName() dynamically loads and initializes classes.
  • ClassNotFoundException indicates the class is missing from the runtime classpath or misnamed.
  • Java’s class loader delegation ensures class uniqueness and security.

With this knowledge, you’ll not only fix exceptions but also write more robust, dynamically loaded Java applications.

9. References#