Dynamic Object Creation

⭐ Interview Importance: MEDIUM
⏱️ Revision Time: 5 min

TL;DR

  • Reflection allows you to instantiate objects at runtime using the Constructor API.
  • This is useful when you only know the class name as a String (e.g., loading a plugin or deserializing JSON).
  • The legacy Class.newInstance() method is deprecated; you should always use Constructor.newInstance().

Concept

Normally, you create objects using the new keyword, which hardcodes the class name into your program.
With Reflection, you can read a class name from a configuration file, get its Class object, find the appropriate constructor, and invoke it to create an instance.

This is the foundation of Dependency Injection frameworks like Spring. Spring reads your @Service and @Repository annotations, finds their constructors via Reflection, dynamically instantiates them, and wires them together.

Examples

import java.lang.reflect.Constructor;

class User {
    private String name;
    
    // Default constructor
    public User() { this.name = "Guest"; }
    
    // Parameterized constructor
    public User(String name) { this.name = name; }
    
    public String getName() { return name; }
}

public class InstantiationDemo {
    public static void main(String[] args) throws Exception {
        
        Class<?> clazz = Class.forName("User");
        
        // 1. Using the No-Arg Constructor
        Constructor<?> defaultConstructor = clazz.getDeclaredConstructor();
        User user1 = (User) defaultConstructor.newInstance();
        System.out.println(user1.getName()); // Prints: Guest
        
        // 2. Using a Parameterized Constructor
        // We must pass the Class objects representing the parameter types
        Constructor<?> paramConstructor = clazz.getDeclaredConstructor(String.class);
        
        // Then we pass the actual argument values to newInstance()
        User user2 = (User) paramConstructor.newInstance("Alice");
        System.out.println(user2.getName()); // Prints: Alice
        
        // 3. Creating a private Singleton dynamically!
        // If the constructor was private, we could just do:
        // paramConstructor.setAccessible(true);
        // And bypass the Singleton pattern entirely!
    }
}

Interview Questions

Q: Why is Class.newInstance() deprecated in Java 9?
A: Historically, you could do User.class.newInstance(). It was deprecated for two major reasons:

  1. It bypasses compile-time exception checking. If the constructor throws a checked exception (like IOException), Class.newInstance() sneakily throws it as an unchecked exception, breaking Java’s exception handling rules. Constructor.newInstance() wraps exceptions properly in an InvocationTargetException.
  2. It can only call the zero-argument constructor.

Q: How do you catch exceptions thrown by a dynamically invoked constructor?
A: When you call constructor.newInstance() (or method.invoke()), and the underlying code inside that constructor throws an exception, Reflection catches it and wraps it inside an InvocationTargetException. To find out what actually went wrong, you must catch the InvocationTargetException and call .getCause() to retrieve the original exception.