Java Reflection: Calling Constructors
Instantiate Java classes reflectively with Constructor.newInstance and Class.getDeclaredConstructor.
Java Reflection: Calling Constructors
Creating an object without writing new is the reflective trick behind every dependency-injection container, deserializer, and plugin loader: you have a Class, and you need an instance. The Constructor<T> object represents one constructor and builds instances with newInstance(args...). This chapter covers finding constructors, calling them with arguments, reaching private constructors, and why the old Class.newInstance() shortcut is deprecated.
Finding constructors
Constructors are looked up by parameter types only — there's no name, since all constructors share the class's name:
Class<User> c = User.class;
Constructor<User> noArg = c.getDeclaredConstructor(); // ()
Constructor<User> twoArg = c.getDeclaredConstructor(String.class, int.class); // (String, int)
Constructor<?>[] pub = c.getConstructors(); // public only
Constructor<?>[] all = c.getDeclaredConstructors(); // any access levelAs everywhere in reflection, parameter types must match exactly (int.class, not Integer.class), and getConstructor sees only public ones while getDeclaredConstructor sees private/protected/package too. Note Constructor<T> is generic in the class it builds, so newInstance returns a typed T (unlike Method.invoke's raw Object).
Building instances with newInstance
Constructor<User> ctor = User.class.getDeclaredConstructor(String.class, int.class);
User u = ctor.newInstance("ada", 36); // returns a typed UserArguments work just like Method.invoke: a varargs Object[], primitives autoboxed. The difference is there's no target object — a constructor creates the target. Exceptions thrown by the constructor body are wrapped in InvocationTargetException, exactly as with methods; unwrap with getCause().
Reaching private constructors
Singletons, utility classes, and builders often hide their constructor. Reflection walks right past that with setAccessible(true):
Constructor<Singleton> ctor = Singleton.class.getDeclaredConstructor();
ctor.setAccessible(true); // bypass the private modifier
Singleton fresh = ctor.newInstance(); // a SECOND instance — breaks the singleton!This is genuinely powerful and genuinely dangerous: it defeats the singleton guarantee, the "no instances" contract of a utility class, and any invariant the constructor was protecting. (An enum singleton is the one form reflection cannot instantiate — Constructor.newInstance explicitly refuses enum types with IllegalArgumentException, which is part of why "enum singleton" is the recommended pattern.)
Why Class.newInstance() is deprecated
You'll see old code use the shortcut clazz.newInstance():
User u = User.class.newInstance(); // DEPRECATED since Java 9It's deprecated for two real reasons:
- It only calls the no-arg constructor. No way to pass arguments.
- It mishandles exceptions. If the no-arg constructor throws a checked exception,
Class.newInstance()propagates it without declaring it — defeating the compiler's checked-exception analysis.
The replacement is always:
User u = User.class.getDeclaredConstructor().newInstance();This is one line longer, calls a constructor you chose explicitly, and wraps constructor exceptions in InvocationTargetException so nothing escapes undeclared. Use it as the standard idiom even for the no-arg case.
A worked example: a tiny reflective factory
The program builds objects three ways: a public multi-arg constructor, a private constructor reached via setAccessible, and the modern no-arg idiom — then shows a constructor that throws being wrapped, and the deprecated shortcut's signature for contrast.
What to take from the run:
- The generic
buildfactory createdWidgetandHiddenfrom aClassplus a parameter-type array — naming neither type in anewexpression. That signature,<T> T build(Class<T>, Class<?>[], Object...), is essentially what a DI container's instantiation core looks like: hand it a type and arguments, get back an instance. getDeclaredConstructor().newInstance()produced the defaultWidget, demonstrating the modern replacement forClass.newInstance(). Always prefer it: it lets you choose the constructor and it routes constructor exceptions throughInvocationTargetExceptioninstead of leaking undeclared checked exceptions.- The reflective
Hiddeninstance was not the same object asHidden.INSTANCE(same instance? false).setAccessible(true)walked straight past theprivateconstructor and minted a second instance — concrete proof that reflection can break a singleton's core guarantee. Defensive singletons throw from the constructor if an instance already exists; enums are immune by construction. - The constructor that rejected a negative size threw
IllegalArgumentExceptionfrom its body, and that surfaced asInvocationTargetExceptionwith the real cause inside — identical wrapping toMethod.invoke. Construction-time validation is preserved through reflection; you just have to unwrap to see it. Constructor<T>returned a typedT(Widget,Hidden) with no cast, unlikeMethod.invoke's rawObject. Because the constructor is generic in the class it builds, the factory stays type-safe at its boundary even though everything inside is reflective.
Practice
A teammate writes 'MyService s = MyService.class.newInstance();' and the linter flags 'newInstance()' as deprecated. What is the recommended replacement, and what is the main practical reason the old form was deprecated?