Class.forName() vs ClassLoader in Java Reflection
Core Difference: Load + Initialize vs Load Only
Class Loading in JVM
Java class loading involves three phases: Loading → Linking → Initialization.
- Loading: Bytecode is read into memory, creating a
Classobject. - Initialization: Static blocks execute and static variable are assigned (
<clinit>method runs).
The two mechanisms differ in which phases they cover:
| Aspect | Class.forName(String) |
ClassLoader.loadClass(String) |
|---|---|---|
| Default behavior | Loads class and triggers initialization | Loads class without initialization |
| Initialization control | Overloaded version Class.forName(name, initialize, loader) allows disabling init |
No control – never triggers init |
| Exception | ClassNotFoundException (checked) |
ClassNotFoundException (checked) |
| Class name format | Fully qualified name (e.g. java.sql.Driver) |
Fully qualified name (same) |
| Implementation | Internally calls ClassLoader, then adds initialization step |
Core loading mechanism; forName depends on it |
Code Demo: Observing the Difference
1. Test class with static block
public class SampleClass {
static {
System.out.println("SampleClass static block executed (initialization)");
}
public static String value = "static field initialized";
}
2. Class.forName() triggers initialization by default
public class DemoForName {
public static void main(String[] args) throws ClassNotFoundException {
Class<?> clazz = Class.forName("com.example.SampleClass");
System.out.println("Class.forName completed");
}
}
Output:
SampleClass static block executed (initialization)
Class.forName completed
3. ClassLoader.loadClass() skips initialization
public class DemoLoader {
public static void main(String[] args) throws ClassNotFoundException {
ClassLoader loader = ClassLoader.getSystemClassLoader();
Class<?> clazz = loader.loadClass("com.example.SampleClass");
System.out.println("ClassLoader.loadClass completed");
// Access static field triggers initialization
System.out.println(SampleClass.value);
}
}
Output:
ClassLoader.loadClass completed
SampleClass static block executed (initialization)
static field initialized
4. Class.forName() with initialization disabled
public class DemoForNameNoInit {
public static void main(String[] args) throws ClassNotFoundException {
Class<?> clazz = Class.forName("com.example.SampleClass", false, ClassLoader.getSystemClassLoader());
System.out.println("Class.forName (init disabled) completed");
}
}
Output:
Class.forName (init disabled) completed
Practical Use Cases
When to use Class.forName()
Loading JDBC drivers is the classic example:
Class.forName("com.mysql.cj.jdbc.Driver");
The driver's static block registers the driver with DriverManager. Initialization must happan, so forName() is appropriate.
When to use ClassLoader
- Lazy initialization – frameworks like Spring or Tomcat load class metadata without triggering static blocks until the class is actually used (e.g., calling a static method or creating an instance).
- Custom class loaders – in scnearios like hot deployment or modular loading, you only want the loading phase, leaving initialization up to the application logic.
Key Takeaways
Class.forName()loads and initializes (configurable);ClassLoader.loadClass()loads only, never initializes.Class.forName()wrapsClassLoaderinternally, adding an initialization step.- Choose
forName()when static code must run eagerly (e.g., driver registration); chooseClassLoaderwhen only the class definition is needed and initialization should be deferred.