Dynamic Object Creation
TL;DR
- Reflection allows you to instantiate objects at runtime using the
ConstructorAPI. - 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 useConstructor.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:
- 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 anInvocationTargetException. - 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.